ISBNをチェックするユーティリティ
唐突に、いつかどこかで役に立つかなぁ、と思い、持てる力(何)をいろいろ出してユーティリティを書いてみた。
アルゴリズムはWikipedia(ISBN - Wikipedia)を参考にした。
Java版
多少のブランクはあってもやはり私のプライマリ言語ということでまず最初に。
- 確認環境:Windows Vista Business + Java 6 SDK 1.6.0_20
/** * ISBN(ISBN-10、ISBN-13)をチェックするユーティリティ。 * * @author hhelibex * @see http://ja.wikipedia.org/wiki/ISBN */ public final class ISBNUtil { private ISBNUtil() { throw new InternalError("class ISBNUtil cannot be instantiated."); } /** * 正しいISBN-10であるかどうかをチェックする。 * * @param isbn10 "nnnnnnnnnc"の形式(nは0-9、cは0-9または'X')、 * または、ハイフン(u002d)かスペース(u0020)が入った形式の文字列。 * @return 正しいISBN-10である場合はtrue、それ以外の場合はfalse */ public static boolean isValidISBN10(String isbn10) { if (isbn10 == null) { return false; } isbn10 = isbn10.replaceAll("[- ]", ""); if (!isbn10.matches("[0-9]{9}[0-9X]")) { return false; } int val = 11 - ( (10 * charToInt(isbn10.charAt(0)) + 9 * charToInt(isbn10.charAt(1)) + 8 * charToInt(isbn10.charAt(2)) + 7 * charToInt(isbn10.charAt(3)) + 6 * charToInt(isbn10.charAt(4)) + 5 * charToInt(isbn10.charAt(5)) + 4 * charToInt(isbn10.charAt(6)) + 3 * charToInt(isbn10.charAt(7)) + 2 * charToInt(isbn10.charAt(8))) % 11); char chk = (val == 10 ? 'X' : (val == 11 ? '0' : intToChar(val))); if (isbn10.charAt(9) != chk) { return false; } return true; } /** * 正しいISBN-13であるかどうかをチェックする。 * * @param isbn13 "nnnnnnnnnnnnn"の形式(nは0-9)、 * または、ハイフン(u002d)かスペース(u0020)が入った形式の文字列。 * @return 正しいISBN-13である場合はtrue、それ以外の場合はfalse */ public static boolean isValidISBN13(String isbn13) { if (isbn13 == null) { return false; } isbn13 = isbn13.replaceAll("[- ]", ""); if (!isbn13.matches("[0-9]{13}")) { return false; } int val = ( 1 * charToInt(isbn13.charAt(0)) + 3 * charToInt(isbn13.charAt(1)) + 1 * charToInt(isbn13.charAt(2)) + 3 * charToInt(isbn13.charAt(3)) + 1 * charToInt(isbn13.charAt(4)) + 3 * charToInt(isbn13.charAt(5)) + 1 * charToInt(isbn13.charAt(6)) + 3 * charToInt(isbn13.charAt(7)) + 1 * charToInt(isbn13.charAt(8)) + 3 * charToInt(isbn13.charAt(9)) + 1 * charToInt(isbn13.charAt(10)) + 3 * charToInt(isbn13.charAt(11))) % 10; char chk = (val % 10 == 0 ? intToChar(0) : intToChar(10 - val)); if (isbn13.charAt(12) != chk) { return false; } return true; } /** * 指定した数字を対応する数値に変換する。 * * @param ch 数字('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') * @return 対応する数値(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) * @throws IllegalArgumentException 指定した文字が数字でない場合 */ private static int charToInt(char ch) throws IllegalArgumentException { int res = "0123456789".indexOf(ch); if (res < 0) { throw new IllegalArgumentException("not a digit character"); } else { return res; } } /** * 指定した一桁の正の数値を対応する数字に変換する。 * * @param n 一桁の正の数値(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) * @return 対応する数字('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') * @throws IllegalArgumentException 指定した数値が一桁の正数でない場合 */ private static char intToChar(int n) throws IllegalArgumentException { if (n < 0 || n > 9) { throw new IllegalArgumentException("not a one digit of number"); } return "0123456789".charAt(n); } }
JavaScript版
中途半端に使っていたので、構文に関する記憶があいまいで、本を眺めながらだったが(謎)。
- 確認環境:Windows Vista Business + Firefox 3.6.8
/** * ISBN(ISBN-10、ISBN-13)をチェックするユーティリティ。 * * @author hhelibex * @see http://ja.wikipedia.org/wiki/ISBN */ (function() { /* * Javaのstaticメソッド呼び出しのように記述するために、 * まずprivate擬似クラスを作成。 */ var ISBNUtilP = function() {}; /** * 正しいISBN-10であるかどうかをチェックする。 * * @param isbn10 "nnnnnnnnnc"の形式(nは0-9、cは0-9または'X')、 * または、ハイフン(u002d)かスペース(u0020)が入った形式の文字列。 * @return 正しいISBN-10である場合はtrue、それ以外の場合はfalse */ ISBNUtilP.prototype.isValidISBN10 = function(isbn10) { if (!isbn10) { return false; } isbn10 = isbn10.replace(/[- ]/g, ""); if (isbn10.length != 10) { return false; } if (!isbn10.match(/^[0-9]+[0-9X]$/)) { return false; } var val = 11 - ( (10 * isbn10.substring(0, 1) + 9 * isbn10.substring(1, 2) + 8 * isbn10.substring(2, 3) + 7 * isbn10.substring(3, 4) + 6 * isbn10.substring(4, 5) + 5 * isbn10.substring(5, 6) + 4 * isbn10.substring(6, 7) + 3 * isbn10.substring(7, 8) + 2 * isbn10.substring(8, 9)) % 11); var chk = (val == 10 ? 'X' : (val == 11 ? '0' : val + '')); if (isbn10.substring(9, 10) != chk) { return false; } return true; } /** * 正しいISBN-13であるかどうかをチェックする。 * * @param isbn13 "nnnnnnnnnnnnn"の形式(nは0-9)、 * または、ハイフン(u002d)かスペース(u0020)が入った形式の文字列。 * @return 正しいISBN-13である場合はtrue、それ以外の場合はfalse */ ISBNUtilP.prototype.isValidISBN13 = function(isbn13) { if (!isbn13) { return false; } isbn13 = isbn13.replace(/[- ]/g, ""); if (isbn13.length != 13) { return false; } if (!isbn13.match(/^[0-9]+$/)) { return false; } var val = ( 1 * isbn13.substring( 0, 1) + 3 * isbn13.substring( 1, 2) + 1 * isbn13.substring( 2, 3) + 3 * isbn13.substring( 3, 4) + 1 * isbn13.substring( 4, 5) + 3 * isbn13.substring( 5, 6) + 1 * isbn13.substring( 6, 7) + 3 * isbn13.substring( 7, 8) + 1 * isbn13.substring( 8, 9) + 3 * isbn13.substring( 9, 10) + 1 * isbn13.substring(10, 11) + 3 * isbn13.substring(11, 12)) % 10; var chk = (val % 10 == 0 ? '0' : (10 - val) + ''); if (isbn13.substring(12, 13) != chk) { return false; } return true; } /* * private擬似クラスのインスタンスを生成する。 */ ISBNUtil = new ISBNUtilP(); })();
PHP版
実際に使い始めてから約1ヶ月だが、それなりに書けるようになってきたような気がする(謎)。
- 確認環境:Windows Vista Business + PHP 5.3.3
<?php /** * ISBN(ISBN-10、ISBN-13)をチェックするユーティリティ。 * * @author hhelibex * @see http://ja.wikipedia.org/wiki/ISBN */ class ISBNUtil { /** * 正しいISBN-10であるかどうかをチェックする。 * * @param isbn10 "nnnnnnnnnc"の形式(nは0-9、cは0-9または'X')、 * または、ハイフン(u002d)かスペース(u0020)が入った形式の文字列。 * @return 正しいISBN-10である場合はtrue、それ以外の場合はfalse */ public static function isValidISBN10($isbn10) { if (!$isbn10) { return false; } $isbn10 = preg_replace('/[- ]/', '', $isbn10); if (strlen($isbn10) != 10) { return false; } if (!preg_match('/^[0-9]+[0-9X]$/', $isbn10)) { return false; } $val = 11 - ( (10 * substr($isbn10, 0, 1) + 9 * substr($isbn10, 1, 1) + 8 * substr($isbn10, 2, 1) + 7 * substr($isbn10, 3, 1) + 6 * substr($isbn10, 4, 1) + 5 * substr($isbn10, 5, 1) + 4 * substr($isbn10, 6, 1) + 3 * substr($isbn10, 7, 1) + 2 * substr($isbn10, 8, 1)) % 11); $chk = ($val == 10 ? 'X' : ($val == 11 ? '0' : $val + '')); if (substr($isbn10, 9, 1) != $chk) { return false; } return true; } /** * 正しいISBN-13であるかどうかをチェックする。 * * @param isbn13 "nnnnnnnnnnnnn"の形式(nは0-9)、 * または、ハイフン(u002d)かスペース(u0020)が入った形式の文字列。 * @return 正しいISBN-13である場合はtrue、それ以外の場合はfalse */ public static function isValidISBN13($isbn13) { if (!$isbn13) { return false; } $isbn13 = preg_replace('/[- ]/', '', $isbn13); if (strlen($isbn13) != 13) { return false; } if (!preg_match('/^[0-9]+$/', $isbn13)) { return false; } $val = ( 1 * substr($isbn13, 0, 1) + 3 * substr($isbn13, 1, 1) + 1 * substr($isbn13, 2, 1) + 3 * substr($isbn13, 3, 1) + 1 * substr($isbn13, 4, 1) + 3 * substr($isbn13, 5, 1) + 1 * substr($isbn13, 6, 1) + 3 * substr($isbn13, 7, 1) + 1 * substr($isbn13, 8, 1) + 3 * substr($isbn13, 9, 1) + 1 * substr($isbn13, 10, 1) + 3 * substr($isbn13, 11, 1)) % 10; $chk = ($val % 10 == 0 ? '0' : (10 - $val) + ''); if (substr($isbn13, 12, 13) != $chk) { return false; } return true; } } ?>
SQL(DB2)版
とりあえず、テーブルの中にISBNが入っているものとして、それをチェックするためのSQL文。
SELECT文で書こうとすると、なかなか手続き的に書けなくて力尽きたので、DB2版のみ。
- 確認環境:Windows Vista Business + DB2 Express-C 9.7.2
テーブル構成は次のものを想定。
CREATE TABLE isbn10s( id INTEGER GENERATED ALWAYS AS IDENTITY , isbn10 VARCHAR(32) NOT NULL) ; CREATE TABLE isbn13s( id INTEGER GENERATED ALWAYS AS IDENTITY , isbn13 VARCHAR(32) NOT NULL) ;
-- ISBN-10 SELECT id, isbn10, CASE WHEN (CASE WHEN val = 10 THEN 'X' WHEN val = 11 THEN '0' ELSE CHAR(val) END) = check THEN 'valid' ELSE 'invalid' END AS isValid FROM TABLE( SELECT id, isbn10, CASE WHEN LENGTH(body) = 9 AND LENGTH(TRIM(TRANSLATE(body, '', '0123456789'))) = 0 THEN 11 - MOD(10 * INTEGER(SUBSTR(body, 1, 1)) + 9 * INTEGER(SUBSTR(body, 2, 1)) + 8 * INTEGER(SUBSTR(body, 3, 1)) + 7 * INTEGER(SUBSTR(body, 4, 1)) + 6 * INTEGER(SUBSTR(body, 5, 1)) + 5 * INTEGER(SUBSTR(body, 6, 1)) + 4 * INTEGER(SUBSTR(body, 7, 1)) + 3 * INTEGER(SUBSTR(body, 8, 1)) + 2 * INTEGER(SUBSTR(body, 9, 1)), 11) ELSE -1 END AS val, CASE WHEN LENGTH(check) = 1 AND check IN ('0','1','2','3','4','5','6','7','8','9','X') THEN check ELSE '' END AS check FROM TABLE( SELECT id, isbn10, TRIM(SUBSTR(REPLACE(REPLACE(isbn10, '-', ''), ' ', ''), 1, 9)) AS body, TRIM(SUBSTR(REPLACE(REPLACE(isbn10, '-', ''), ' ', ''), 10)) AS check FROM isbn10s ) AS T1 ) AS T2 ORDER BY id ; -- ISBN-13 SELECT id, isbn13, CASE WHEN (CASE WHEN MOD(val, 10) = 0 THEN '0' ELSE CHAR(10 - val) END) = check THEN 'valid' ELSE 'invalid' END AS isValid FROM TABLE( SELECT id, isbn13, CASE WHEN LENGTH(body) = 12 AND LENGTH(TRIM(TRANSLATE(body, '', '0123456789'))) = 0 THEN MOD( 1 * INTEGER(SUBSTR(body, 1, 1)) + 3 * INTEGER(SUBSTR(body, 2, 1)) + 1 * INTEGER(SUBSTR(body, 3, 1)) + 3 * INTEGER(SUBSTR(body, 4, 1)) + 1 * INTEGER(SUBSTR(body, 5, 1)) + 3 * INTEGER(SUBSTR(body, 6, 1)) + 1 * INTEGER(SUBSTR(body, 7, 1)) + 3 * INTEGER(SUBSTR(body, 8, 1)) + 1 * INTEGER(SUBSTR(body, 9, 1)) + 3 * INTEGER(SUBSTR(body, 10, 1)) + 1 * INTEGER(SUBSTR(body, 11, 1)) + 3 * INTEGER(SUBSTR(body, 12, 1)), 10) ELSE -1 END AS val, CASE WHEN LENGTH(check) = 1 AND check IN ('0','1','2','3','4','5','6','7','8','9') THEN check ELSE '' END AS check FROM TABLE( SELECT id, isbn13, TRIM(SUBSTR(REPLACE(REPLACE(isbn13, '-', ''), ' ', ''), 1, 12)) AS body, TRIM(SUBSTR(REPLACE(REPLACE(isbn13, '-', ''), ' ', ''), 13)) AS check FROM isbn13s ) AS T1 ) AS T2 ORDER BY id ;
続きはまたいつか(何時)。