最後の日は最後の一桁を埋めるAlgorithm::CheckDigitsB!

メリクリ!メリクリ!piarraです。

Advent Calendar最後の日は、最後の一桁を埋めるCPANモジュール「Algorithm::CheckDigits」をご紹介します。

このモジュールについて、日本語で紹介されているブログ等を見つけられなかったので、敢えて選んでみました。

こんな経験はありませんか?

  • 7桁しかないidを8桁にしたいのだけれど、8桁目を0やランダム値にするのはどうよと思ったとき
  • なんらかの理由で連番ではないidの生成をしたいとき
  • JANコードを発行したいのに、何故か12桁しか作れなくって、最後の一桁は自分で作れっていわれても…?なとき
  • クレジットカードの右端が12mm折れてしまって放置していたら、いつの間にかその破片をなくしてしまったけれど、取り急ぎネットで本を買いたいのに、クレジットカードの最後の一桁がどうしても分からないとき

そんなときは、Algorithm::CheckDigitsの出番です。

チェックデジットとは

さて、「CheckDegit(チェックデジット)」という言葉に馴染みのない方もいらっしゃると思うので、まずは基本的なお話から。

Wikipediaによると、

「チェックディジット(check digit, 検査数字)とは、
符号の入力誤りなどを検出するために元の符号に付加される数字のこと。」

とされています。

馴染みの深いところでは、バーコードなどで読み取りミスを防ぐために、最後の一桁にチェックデジットを付与して、データを誤って読み取ってしまうことを防いでいます。

例えば、「初めてのPerl」のISBN"978-4-87311-126-1"の最後の"1"はチェックデジットです。

計算してみる

まずは実際に上のISBNコードのチェックデジットを計算してみます。

ISBNコードやJANコードは、「モジュラス10 ウェイト3・1」というアルゴリズムで算出されます。

このアルゴリズムでは、"左から奇数桁の数字の合計"と、"偶数桁の数字の合計を3倍にしたもの"を加え、10からその和の下一桁の数字を引いてチェックデジットを求めます。

(9 + 8 + 8 + 3 + 1 + 2) + (7 + 4 + 7 + 1 + 1 + 6) * 3 = 109 ・・・下一桁は9
10 - 9 = 1 ・・・ この1がチェックデジット

確かに計算結果と実際の値とが一致しました。比較的簡単な計算のアルゴリズムですね。

Perl登場|・ω・)ノ

Perlの苦手な方はチェックデジットくらい暗算をするみたいですが、

小学校を卒業した賢いCasual Perlerの皆さんは当然Perlを使いますよね。

というわけで、Perlで簡単にチェックデジットを付与し、あるいは検証するモジュールの紹介です。

Algorithm::CheckDegits

use Algorithm::CheckDigits;

my $isbn13 = CheckDigits('ISBN13');
if ($isbn13->is_valid('978-4-87311-126-1')) {
    # OK
}

my $lp_isbn = $isbn13->complete('978-4-87311-126');
print $lp_isbn . "\n";

上の通り、CheckDigits()関数にて付与したいチェックデジットの種類を指定します。

ここでは、13桁の新ISBNコードを使っていますので、"ISBN13"という指定をしています。

他には、クレジットカードの"VISA"や"AMEX"、"DINERS"、Amazon等でおなじみの"EAN"(JANもこれと同じ)などが指定できます。

指定できるアルゴリズム名の一覧は、

my @ml = Algorithm::CheckDigits->method_list();

で取得できます。

ちなみに、m10_005などという命名がなされていますが、それは必ずしも名前通りモジュラス10ウェイト5という意味ではないようですので注意が必要です。

※実際にはm10_004がモジュラス10ウェイト3.1に該当、m10-005がモジュラス10ウェイト4.9に該当など

実際のアルゴリズムを確認したい場合は、以下のようにperldocを参照するか、ソースをご覧ください。

perldoc Algorithm::CheckDigits::M10_005

様々な用途

チェックデジットというのは、数値の検証に用いるのが本来の用途だと思いますが、それ以外にも私自身は以下のような用途で使っています。

  • IDの桁数を揃えたい場合で、桁数に余裕があり、かつ連番やゼロを避けたいとき(00001,00002,00003...よりも00016,00025,00034...とすることで連番を避けた様に見える)
  • JANコードやISBN等を保存する際、1文字分の容量を節約したいとき
  • 彼女の誕生日の下一桁を忘れたとき

クリスマスチェックデジット

チェックデジットでクリスマスがcompleteできるか遊んでみました。

my $christmas = CheckDigits('EAN');
print $christmas->complete('2009122'); # 結果はご自身でご確認ください:)

最後に

さて、25日間にわたってお楽しみいただいたJperl Advent Calendar - Casual Trackも今日で最後となりました。

毎日欠かさずチェックいただいたcasual perlerやperl hackerの皆さんありがとうございました。

そして、今日まで途切れることなくバトンをつないで頂いたcasual perlerの皆様お疲れ様でした。

また来年のAdvent Calendarに参加できることを楽しみにしています。

それでは、皆様良いお年を。

Special Thanks

id:kimury