読者です 読者をやめる 読者になる 読者になる

酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

C#でISBN-13からISBN-10へ変換する/ISBN-10からISBN-13へ変換する

個人的にネットで書籍を買う時に使うのが楽天ブックスとAmazonです。

どちらのショップでもISBNの表記を見つけられるはずです。ISBNとは書籍を管理する番号です。ISBNの規格には10桁で管理するISBNと13桁で管理するISBN-13が存在しています。

基本的にはISBN-10は旧規格とされ、現在ISBN-13へ移行が完了しています。しかし、AmazonではISBN-10とISBN-13を併記しているのですが、URLからも見て取れるようにISBN-10を使い続けています。

「進撃の巨人」の最新刊を例にとってみましょう。

DVD付き 進撃の巨人 (13)限定版 (講談社キャラクターズA)

DVD付き 進撃の巨人 (13)限定版 (講談社キャラクターズA)

下図が楽天ブックスでの表記です。ISBN-13だけが記載されています。

f:id:ch3cooh393:20140217144453p:plain

下図はAmazonの商品説明欄です。ISBN-10とISBN-13が併記されています。

f:id:ch3cooh393:20140217144502p:plain

このように相互に変換なケースがまれに発生します。そこでお互いに変換するコードを書いてみました*1

コードは以下の通りです。 穴だらけなので実際に使うときはもう少し入力値のチェックを増やしてあげてください。

ISBN-13からISBN-10へ変換する

public static string ConvertToISBN10(string isbn13)
{
    if (string.IsNullOrWhiteSpace(isbn13) || isbn13.Length != 13)
    {
        throw new ArgumentException();
    }

    var sum = isbn13.Skip(3).Take(9)
        .Select((item, index) => int.Parse(item.ToString()) * (10 - index))
        .Sum(item => item);

    var digit = string.Empty;
    var c = 11 - (sum % 11);
    if (c == 10)
    {
        digit = "X";
    }
    else if (c == 11)
    {
        digit = "0";
    }
    else
    {
        digit = c.ToString();
    }

    return string.Format("{0}{1}", isbn13.Substring(3, 9), digit);
}

ISBN-10からISBN-13へ変換する

public static string ConvertToISBN13(string isbn10)
{
    if (string.IsNullOrWhiteSpace(isbn10) || isbn10.Length != 10)
    {
        throw new ArgumentException();
    }

    var sum = isbn10.Insert(0, "978")
        .Take(12)
        .Select((item, index) => int.Parse(item.ToString()) * (((index + 1) % 2 == 1) ? 1 : 3))
        .Sum(item => item);

    var digit = string.Empty;
    var check = 10 - (sum % 10);
    if (check == 10)
    {
        digit = "0";
    }
    else
    {
        digit = check.ToString();
    }

    return string.Format("978{0}{1}", isbn10.Substring(0, 9), digit);
}

追記:GitHubにリポジトリ作成しました

Xamarin.Android、Xamarin.iOSでも使えるようにPCL化したプロジェクトを作成しました。

PCLではstringを文字ごとにLINQで扱うコードが書けなかったので、前述したコードと比較すると若干変更点があります。

*1:後で見返したけどあんまり説明になってなかった