Windowsバッチファイルでマイナンバーのチェックデジットを計算
Visual Batを入れてみたことだし、使い勝手の検証のためになんかいいものはないかなと思ったらこんな記事を見つけました。
ちょっと流行(?)に乗り遅れた感じがしますね。
でもそもそもバッチファイル自体が流行以前の問題なので問題ないですね。
計算方法やらなんやらは上記サイトを参照してください。
というわけで、早速書いてみました。なんか割りと試行錯誤しすぎてかなり汚いコードになってます。
もっと綺麗に書けるかもしれないんで、わかる方がいたらコメントいただけないでしょうか?
マイナンバーのチェックデジット計算
@echo off REM validate_mynumber.bat REM マイナンバーのチェックサムを検証する REM 参考:http://qiita.com/qube81/items/fa6ef94d3c8615b0ce64 setlocal enabledelayedexpansion call :calc_strlen %1 if %strlen% neq 12 echo requires 12-digit input & goto end set mynumber=%1 set check_digit=%mynumber:~-1% set /a sum=0 set temp=%mynumber:~0,-1% for /l %%I in (1,1,11) do ( if %%I leq 6 ( set /a q=%%I+1 ) else ( set /a q=%%I-5 ) set p=!temp:~-1! set /a sum+=!p!*!q! set temp=!temp:~0,-1! ) set /a remainder=!sum!%%11 if !remainder! leq 1 ( set check=0 ) else ( set /a check=11-!remainder! ) if !check_digit! equ !check! ( echo true ) else ( echo false ) goto end :calc_strlen set str=%1 set strlen=0 :loop_calc if defined str ( set str=%str:~1% set /a strlen+=1 goto :loop_calc ) exit /b :end endlocal
検証用バッチファイル
@echo off setlocal enabledelayedexpansion set number=12345678901 for /l %%I in (0,1,9) do ( echo input:%number%%%I call validate_mynumber %number%%%I ) endlocal
検証結果
$ test.bat input:123456789010 false input:123456789011 false input:123456789012 false input:123456789013 false input:123456789014 false input:123456789015 false input:123456789016 false input:123456789017 false input:123456789018 true input:123456789019 false
ちゃんと、8の時にtrueになっているので合っているようですね。
一応、自分のマイナンバーも入力してみましたがしっかりtrueが返ってきたのでよかった(返ってこないと大問題)
追記
各言語の実装をまとめられる方からコメントをいただきました。
参考までに現在どのような言語でマイナンバーのチェックデジット計算が実装されているか、自分はここにはない別の言語で実装してやるなんかの参考にもどうぞ
C++でマイナンバーのチェックデジットを計算する - Qiita
解説
処理の解説がないのは少々不親切なので追記
文字数の計算
Batファイルにはそもそも文字列長を計算してくれるような機能はありません
なので少々強引に文字列長の計算をする処理を:calc_strlen
ラベル以下に記述しています。
:calc_strlen set str=%1 set strlen=0 :loop_calc if defined str ( set str=%str:~1% set /a strlen+=1 goto :loop_calc ) exit /b
今回は処理を簡略化するために第1引数以外を無視しています。
:calc_strlen
が文字列長を計算し、strlen
という変数に文字列長を代入します。
%1
は第1引数
if defined str
はバッチファイルの仕様上、空でなければ定義されているという扱いになるため変数str
が空になるまでループさせ、変数strlen
をインクリメントする処理になっています。
%str:~1%
:これは、str
の1文字目から最後までを取得という意味。0文字目開始なので、ループ中で空になるまで1文字ずつシフトしています。
if %strlen% neq 12
はそのままstrlen
が12じゃなかったらという意味ですね。
今回扱いたい文字列長は12桁の数値なので12文字以外は処理を行わないようにしています。
バッチファイルで使用できる比較演算子については、コマンドプロンプトでif /?
などと入力していただければ確認できるので省略します。
初期化処理
set mynumber=%1 set check_digit=%mynumber:~-1% set /a sum=0 set temp=%mynumber:~0,-1%
特に解説すべきところはなさそうですが、2行目についてset check_digit=%mynumber:~-1%
の部分は、最後から1文字目から最後まで文字列を取得
また、set temp=%mynumber:~0,-1%
の部分は、0文字目から最後から1文字目までの文字列を取得しています。
バッチファイルの文字列は0文字目を起点とするため、変数名:
の後に0以上の数値を指定することで指定した位置からの文字を取得することができます。
同様に、変数名:(開始位置),(終了位置)
とすることで開始位置から終了位置までの文字列を取得することができます。
また0以上の数値を指定すると開始位置からの文字数、負の値を指定すると終了位置からの文字数を指定することができます。
これらのことを利用して検証用のチェックデジットと計算に使用するための数字を分割しています。
計算・検証
for /l %%I in (1,1,11) do ( if %%I leq 6 ( set /a q=%%I+1 ) else ( set /a q=%%I-5 ) set p=!temp:~-1! set /a sum+=!p!*!q! set temp=!temp:~0,-1! )
まず前半部分です。FOR文の使用方法についてもfor /?
とすることで確認可能なので省略
今回、!(変数名)!
という表記が出てきていますがこちらは変数の遅延展開*1を使用しています。
この辺りから遅延展開というものを使わないとどうやらうまく計算されなくてドハマリしてました。
ただ計算内容自体は参考にしたRuby版と同様で、i≦6の場合はi+1を、i>7の場合はi-5をqとして、検証用に計算しているだけですね。
set /a remainder=!sum!%%11 if !remainder! leq 1 ( set check=0 ) else ( set /a check=11-!remainder! ) if !check_digit! equ !check! ( echo true ) else ( echo false )
最後は特筆すべき点はありませんね。
少しわかりにくいところとしてはバッチファイルを書く場合の注意点が1点含まれているところでしょうか?
剰余の計算が他の言語同様に%
として使用できるのですが、バッチファイルでは%
を表す場合は%%
と重ねて書かなければなりません。
なので%%
と二重に書いています。
さて解説は以上のとおりとなります。
いかがでしたでしょうか?バッチファイルは本来計算が得意な言語(?)ではありませんが工夫次第で色々なことができそうですね。
追記(2016-03-07)
Awk版を作成しました。
awkでマイナンバーのチェックデジットを検証・集計 - 沖の雑記帳
WinBatch版及びAwk版をそれぞれGitHubにあげてみました。
okiworks (Hironao Oki) · GitHub
追記(2016-04-11)
このページも含めリンクしてくださっている、yumedotoさんのページリンクを追加
様々な言語での実装状況まとめも作成されています。
*1:使用直前で変数が更新される。遅延展開しない場合は最初にセットされた値