ISBN-13とISBN-10を相互に変換する。Amazonの紙の本のASINはISBN-10

本記事にはアフィリエイト広告(PR)を含みます。詳しくは広告・アフィリエイトについてをご確認ください。

本の ISBN には、13桁の ISBN-13 と、10桁の ISBN-10 があります。今の本には ISBN-13 が付いていますが、Amazon の紙の本の商品番号(ASIN)は ISBN-10 と同じ番号です。このサイトでも、ISBN-13 から ISBN-10 を計算して、Amazon へのリンクを作っています。

この記事では、2つの ISBN の関係と、相互に変換する JavaScript のコードを紹介します。コードは実際に動かして、結果を確かめたものです。

ISBN-13 と ISBN-10 の関係

ISBN-13 は、ISBN-10 の先頭に「978」を付けて、最後の1桁(チェックディジット)を計算し直したものです。

『リーダブルコード』を例にすると、次のようになります。

ISBN-10:     4-87311-565-5
ISBN-13: 978-4-87311-565-8

真ん中の「4-87311-565」は同じで、先頭の「978」と最後の1桁だけが違います。最後の1桁は、番号の打ち間違いを見つけるための検査用の数字で、ISBN-10 と ISBN-13 では計算の方法が違います。そのため、先頭を付けたり外したりするだけでは変換できず、最後の1桁を計算し直す必要があります。

なお、979 で始まる ISBN-13 には、対応する ISBN-10 がありません。ISBN-10 は 978 の範囲の番号にしか対応していないからです。

チェックディジットの計算

ISBN-13 の場合

最後の1桁を除いた12桁に、左から順に 1、3、1、3、と重みを掛けて足します。合計を10で割った余りを、10から引いた数がチェックディジットです。余りが0のときは、チェックディジットも0になります。

ISBN-10 の場合

最後の1桁を除いた9桁に、左から順に 10、9、8、と1ずつ小さくなる重みを掛けて足します。合計を11で割った余りを、11から引いた数がチェックディジットです。結果が11のときは0、10のときは数字の代わりに「X」を使います。

この「X」が曲者です。11で割るので、10桁目は0から10までの11通りになり、10を1文字で表すために X を使います。このサイトに登録している本では、13冊のうち4冊の ISBN-10 が X で終わりました。ISBN-10 を数字として扱う処理を書くと、これらの本で壊れます。

変換するコード

ハイフン付きの ISBN もそのまま受け取れるように、最初にハイフンと空白を取り除いています。

/** ハイフンや空白を取り除く */
const normalize = (isbn) => isbn.replace(/[-\s]/g, "").toUpperCase();

/** ISBN-13 のチェックディジットを求める(12桁を受け取る) */
const isbn13CheckDigit = (first12) => {
  const sum = [...first12].reduce(
    (acc, digit, index) => acc + Number(digit) * (index % 2 === 0 ? 1 : 3),
    0,
  );
  return String((10 - (sum % 10)) % 10);
};

/** ISBN-10 のチェックディジットを求める(9桁を受け取る) */
const isbn10CheckDigit = (first9) => {
  const sum = [...first9].reduce((acc, digit, index) => acc + Number(digit) * (10 - index), 0);
  const check = (11 - (sum % 11)) % 11;
  return check === 10 ? "X" : String(check);
};

/** ISBN-13 から ISBN-10 へ。978 で始まらない場合は null */
export const toIsbn10 = (isbn13) => {
  const value = normalize(isbn13);
  if (!/^978\d{10}$/.test(value)) return null;
  const body = value.slice(3, 12);
  return body + isbn10CheckDigit(body);
};

/** ISBN-10 から ISBN-13 へ。形式が違う場合は null */
export const toIsbn13 = (isbn10) => {
  const value = normalize(isbn10);
  if (!/^\d{9}[\dX]$/.test(value)) return null;
  const first12 = "978" + value.slice(0, 9);
  return first12 + isbn13CheckDigit(first12);
};

/** チェックディジットまで含めて正しい ISBN-13 か */
export const isValidIsbn13 = (isbn13) => {
  const value = normalize(isbn13);
  return /^97[89]\d{10}$/.test(value) && isbn13CheckDigit(value.slice(0, 12)) === value[12];
};

動かした結果

実際の本の ISBN で試すと、次のようになりました。

toIsbn10("978-4-87311-565-8"); // "4873115655"(リーダブルコード)
toIsbn10("9784816366307"); // "481636630X"(末尾が X になる本)
toIsbn13("4873115655"); // "9784873115658"
toIsbn13("481636630X"); // "9784816366307"
isValidIsbn13("978-4-87311-565-8"); // true
isValidIsbn13("9784873115659"); // false(最後の1桁を変えたもの)
toIsbn10("9791234567896"); // null(979 で始まる番号)

ISBN-13 から ISBN-10 に変換して、また ISBN-13 に戻すと、元の番号に戻ります。最後の1桁をわざと変えた番号は、isValidIsbn13 で false になります。

Amazon のリンクに使うときの注意

紙の本の ASIN は ISBN-10 と同じなので、https://www.amazon.co.jp/dp/ のあとに ISBN-10 を付けると、その本の商品ページになります。このサイトの本のカードも、この形でリンクを作っています。

ただし、Kindle 版の ASIN は ISBN とは関係のない番号です。Kindle 版へのリンクを作りたいときは、商品ページで ASIN を確かめて、別に持っておく必要があります。

⎇ main✓ 13 deps9 articles
UTF-8LFMDX