🗺

[Golang] 日本の住所かどうかを判定する

不完全なのだけど、使えなくもなさそうだから書き残しておく


なにがしたいの

世界各国の住所が入力されるフォームがあって、そこで日本の住所が入力されたときだけ特定の処理を実行したい。 つまり、海外の住所と日本の住所を判別したい

jpn := "東京都千代田区永田町1丁目7−1"
eng := "228 Runamuck Pl #2808, Baltimore, Baltimore City, MD"
ger := "Ruppertstr. 11, 80466 München"
chn := "中国山东省济南市西区10路10号20-10"

isDomesticAddress(jpn) // true
isDomesticAddress(eng) // false
isDomesticAddress(ger) // false
isDomesticAddress(chn) // false

第 1 段階

漢字が使われている住所以外を弾く。この時点で、中国語や朝鮮語以外を弾ける

jpn := "東京都千代田区永田町1丁目7−1"
eng := "228 Runamuck Pl #2808, Baltimore, Baltimore City, MD"
ger := "Ruppertstr. 11, 80466 München"
chn := "中国山东省济南市西区10路10号20-10"

regexpDomesticAddress := regexp.MustCompile(`[\p{Han}]`)
regexpDomesticAddress.MatchString(jpn) // true
regexpDomesticAddress.MatchString(eng) // false
regexpDomesticAddress.MatchString(ger) // false
regexpDomesticAddress.MatchString(chn) // true これはまだ弾けない

第 2 段階

繁体字または簡体字が使われている住所を弾く。日本でも使われている漢字だけで構成された住所は知らん

日本の漢字から繁体字と簡体字を頑張って取り除いていた人もいた1けど、今回はかんたんそうな方法2を選んだ。 どうするかというと、S-JIS に繁体字と簡体字が含まれていないことを利用する。UTF-8 から S-JIS に変換したときに、すべての文字が変換できれば日本語、変換できない文字があれば中国語となる

jpn := "東京都千代田区永田町1丁目7−1"
chn := "中国山东省济南市西区10路10号20-10"

isDomesticAddress := func(address string) bool {
	t := japanese.ShiftJIS.NewEncoder()
	_, _, err := transform.Bytes(t, []byte(s))
	if err != nil {
		// 変換に失敗した=中国語
		return false
	}
	return true
}

isDomesticAddress(jpn) // true
isDomesticAddress(chn) // false

今回の完成形

組み合わせるとこんな感じだろうか。これで 100% 判別できる自信はまったくない

regexpDomesticAddress := regexp.MustCompile(`[\p{Han}]`)

jpn := "東京都千代田区永田町1丁目7−1"
eng := "228 Runamuck Pl #2808, Baltimore, Baltimore City, MD"
ger := "Ruppertstr. 11, 80466 München"
chn := "中国山东省济南市西区10路10号20-10"

isDomesticAddress := func(address string) bool {
	if !regexpDomesticAddress.MatchString(address) {
		return false
	}

	t := japanese.ShiftJIS.NewEncoder()
	_, _, err := transform.Bytes(t, []byte(s))
	if err != nil {
		// 変換に失敗した=中国語
		return false
	}
	return true
}

isDomesticAddress(jpn) // true
isDomesticAddress(eng) // false
isDomesticAddress(ger) // false
isDomesticAddress(chn) // false

正規表現を使えばいいのでは

調べると日本の住所をあらわす正規表現がみつかる3のだけど、これでは不完全な日本の住所を弾いてしまう(今回は「東京都」みたいな不完全な住所も入力される可能性があった)ので、今回は使っていない(まぁそれでもこの正規表現でやりようはあったかもしれない)

^((北海道|東京都|(大阪|京都)府|(神奈川|和歌山|鹿児島)県|[^\s\w\d ]{2}県)[^\s\w\d ]{1,6}[市郡区町村][^\s\w\d ]{1,20}[\d 0-9〇一-九十上下東西]+[^\s '”<)」】]\*)|^((北海道|東京都|(大阪|京都)府|(神奈川|和歌山|鹿児島)県|[^\s\w\d ]{2}県)[^\s\w\d ]{1,6}[市郡区町村][^\s\w\d ]{1,20})