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 を確かめて、別に持っておく必要があります。