Status Code 303 - See Other

Java, C, C++, C#, Objective-C, Swift, bash, perl, ruby, PHP, Python, Scala, Groovy, Go, DevOps, Raspberry Pi など。情報の誤りや指摘・意見などは自由にどうぞ。

Java でのマイナンバーのチェックデジット作成メソッド

概要

http://www.soumu.go.jp/main_content/000327387.pdf
上記第五条に定義があり、そこでは、個人番号を構成する11桁の番号
およびその検査用数字(チェックデジット)で構成されるらしい。
そこで、11桁の番号からチェックデジットを計算するメソッドを作成してみる。

詳細内容

今回作成したチェックデジットを取得するメソッド(getCheckDigitメソッド)。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {

	public static void main(String[] args) throws IOException {
		// 使用例.
		// 標準入力からマイナンバーを拾って、そのチェックデジット値を標準出力に表示.
		String str;
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		while ((str = br.readLine()) != null) {
			System.out.println(getCheckDigit(str));
		}
	}

	/**
	 * マイナンバー(チェックデジットを除く)からチェックデジットを取得する.
	 *
	 * @param myNumber
	 *            マイナンバー(正規表現 {@code "^[0-9]{11}$" } にマッチングする文字列)
	 * @return チェックデジット({@code 0 <= x && x < 10} を満たす整数 x)
	 * @throws NullPointerException
	 *             myNumber が null だった場合.
	 * @throws IllegalArgumentException
	 *             myNumber が null ではないが,11桁の番号で構成されていない場合.
	 */
	public static int getCheckDigit(String myNumber) {
		Matcher m = Pattern.compile("^([0-9]{11})$").matcher(myNumber);
		if (m.find()) {
			long value = Long.parseLong(m.group(1));
			int sum = 0;
			for (int i = 1; i <= 11; i++) {
				sum += (value % 10) * (i < 7 ? i + 1 : i - 5);
				value /= 10;
			}
			int rem = sum % 11;
			return rem <= 2 ? 0 : 11 - rem;
		}
		throw new IllegalArgumentException("My number must be 11-digit number.");
	}
}

説明するほどではないと思うが、一応、メソッド説明。

まずは、入力値の正当性を評価する。

	Matcher m = Pattern.compile("^([0-9]{11})$").matcher(myNumber);
	if (m.find()) {
		(中身は省略)
	}
	throw new IllegalArgumentException("My number must be 11-digit number.");

もし、Matcherが番号11桁を認識しなければ(m.find()で false を返すとき)、IllegalArgumentException が発生して終了する。
また、入力値(myNumber)が null だったら、matcherメソッドで NullPointerException が発生する。
これで、if文の内部の処理が動作するときは、myNumberが番号11桁であることが保証される。

なお、入力値に数値以外が入っているか、数字の桁が足りないかを判断したいときは、

	Matcher m = Pattern.compile("^([0-9]+)$").matcher(myNumber);
	if (m.find()) {
		if(myNumber.length() == 11) {
			(チェックデジットの作成処理)
		}else {
			// 数値が11桁でないときの処理
		}
	}
	// 数値以外の文字が含まれていたときの処理

のように変更すれば良い。今回は両方を一つの例外で扱っている。

次に、チェックデジットを算出する。第五条では、
====================================================
算式 {\displaystyle 11-(\sum_{n=1}^{11} P_n \times Q_n}{11}で除した余り {)}
ただし、{\displaystyle \sum_{n=1}^{11} P_n \times Q_n}{11}で除した余り {\le 1} の場合は、 {0} とする。

算式の符号
{P_n} 個人番号を構成する検査用数字以外の11桁の番号の最下位の桁を{1}桁目としたときの {n} 桁目の数字
{Q_n} {1\le n \le 6} のとき {n+1}{7\le n \le 11}のとき、{n-5}
====================================================
とあるので、これを実装する。

	int sum = 0;
	for (int i = 1; i <= 11; i++) {
		sum += (value % 10) * (i < 7 ? i + 1 : i - 5);
		value /= 10;
	}

この部分で、{\displaystyle \sum_{n=1}^{11} P_n \times Q_n}を作成。

なお、{P_n} に該当するのが、value % 10 (最下位桁の数値を取得)。
{Q_n} に該当するのが、i < 7 ? i + 1 : i - 5 (7桁目未満はその桁数+1、それ以外はその桁数から-5)。
そして、次の処理時に{P_n}の最下位桁を次の桁に設定するために、valueを10で割ってから次の処理に動いている。

あとは、さきほど計算した値の11で除した余りが1以下であるなら0を返し、それ以外は、
{\displaystyle 11-(\sum_{n=1}^{11} P_n \times Q_n}{11}で除した余り{)}を下記 return 文で返すようにしている。

	int rem = sum % 11;
	return rem <= 1 ? 0 : 11 - rem;