本題に入る前に、近況から。
7/29(金)は翔泳社様主催のデベロッパーズサミット2016夏で弊社の相蘇とペアで登壇させていただきました。
弊社製品の紹介とIoTデバイスやビーコンのアプリを少ない工数で実装するライブデモを行ったのですが、心拍計をつけたデモンストレーションでは今回も心拍数が120前後まで上がるという有様で、相変わらず人前でのデモを行う際の緊張状況がバッチリ可視化されてしまいました orz。
なお、心拍計つながりで他のネタを紹介しますが、心拍計とお化け屋敷と組み合わせた「スマートお化け屋敷」というイベントが大阪と沖縄で行なわれているそうです。入場者にIoTデバイスを装着してもらって、どんな場所でどれくらいビビっていたかを可視化してくれるようです。こういうのは実に面白い応用事例ですよね。
https://www.ntt-west.co.jp/ikouze/obake/
さて、近況はそれくらいにしておきまして、話を戻します。日本で昨年からマイナンバーという仕組みが始まりましたが、番号の発行で使われているチェックデジットのアルゴリズムが入力ミスのチェックに対して十分ではない、という話が一部で話題になっているようです。
そしてそういう話題の中で「実装がシンプルで、かつチェックデジットとしても優れている Damm みたいなのを使えばよいのに」という話もあるようです。
私自身は Damm についての知識はなかったのですが、少々気になったので、Damm を Delphi で記述した実装例がないかと思って探してみました。しかし 2016/07/30 時点では実装例が見当たりませんでした。(その他のいくつかの言語での実装例は https://en.wikibooks.org/wiki/Algorithm_Implementation/Checksums/Damm_Algorithm に出ています。)
そこで Damm を Delphi で実装してみたらどうなるかを試してみたのが以下のコードです。ご覧いただければ分かる通り、確かに実装は非常にシンプルでした。変換用の2次元配列を初期化した後は、配列の添字に値を当てはめていくだけです。
この実装の使い方ですが、Damm.encode( [numeric_string] ) で、チェックデジットの数値が取得できます。たとえば 572 という値を文字列で与えるとチェックデジット 4 が戻り値で返されます。
また Damm.check( [numeric] ) では、チェックデジットを含む数値文字列が正しいかどうかを検証できます。先の例で 572 のチェックデジットが 4 と分かっていますが、この処理に 5724 を入力値として与えると True が帰ります。なお、この検証は「チェックデジットを含む文字列をDammでエンコードすると必ず0になる」という仕組みで行います。だから check の処理では encode の結果が 0 かどうかを確認しています。
// // Example Delphi implementation for Damm checkdigit algorithm // // https://en.wikipedia.org/wiki/Damm_algorithm // https://ja.wikipedia.org/wiki/Damm%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0 unit Damm; interface uses System.SysUtils; function encode(Number: String ): Integer; function check(Number: String ): Boolean; implementation function encode(Number: String): Integer; // input: numeric string. // return: check digit by damm const matrix: array[0..9, 0..9] of integer = ( (0, 3, 1, 7, 5, 9, 8, 6, 4, 2), (7, 0, 9, 2, 1, 5, 4, 8, 6, 3), (4, 2, 0, 6, 8, 7, 1, 3, 5, 9), (1, 7, 5, 0, 9, 8, 3, 4, 2, 6), (6, 1, 2, 3, 0, 4, 5, 9, 7, 8), (3, 6, 7, 4, 2, 0, 9, 5, 8, 1), (5, 8, 6, 9, 7, 2, 0, 1, 3, 4), (8, 9, 4, 5, 3, 6, 2, 0, 1, 7), (9, 4, 3, 8, 6, 1, 7, 2, 0, 5), (2, 5, 8, 1, 4, 3, 6, 7, 9, 0) ); var interim: Integer; index: Integer; begin interim := 0; for index := 1 to length(Number) do interim := matrix[ interim, StrToInt(Number[index]) ]; Result := interim; end; function check(Number: String): Boolean; // input: numeric string with damm checkdigit. // return: true if input value is valid number with check digit. begin if ( encode( Number ) = 0 ) then Result := True else Result := False; end; end.
なお、Damm のアルゴリズム自体の解説はここでは省略します。Wikipedia 上の文書やその他の文書等を参照してください。
* 今回のブログでは docwki 関連のネタを書くつもりでしたが、内容の整理が追いついていないので次回に持越しとさせていただきます……。