Unicodeとバリデーション

Date2026/10/08 Last Modified2026/10/08

概要

とあるETLのシステムにおいて、たびたびエラーが発生しており、聞いてみるとこんな感じだった。
「漢字を入れてるのに全角と認識されない」
「名前に記号を入れてくる人を何とかしてほしい」

起こった各事象について調べてみたら理解はできたのだが、あんまり文字コードとかはよく知らないなと感じた。
せっかくの機会なので、今後のためにも詳しく調べてみようと思った。

UnicodeとUTF-8

「文字コード」という言葉を使って、「Unicode」や「UTF-8」の話をすることが多いけれども、実際は微妙に区分が違うらしい。

用語 役割 例
文字集合 どんな文字を扱うか Unicode, JIS X 0208
コードポイント 各文字に付けた番号 U+0041, U+3042
文字エンコーディング 番号をどうバイト列にするか UTF-8, Shift_JIS

普段よく耳にする文字化けの話は「文字エンコーディング」のほう。
今回、バリデーションで範囲を区切りたいのは「文字集合」のほうだった。
文字コードという呼び方は慣習によるもので、少し広い意味を扱っていたみたい。

UnicodeとJIS水準

一つ話題に上がったのは「異体字」の扱いである。
例えば「高橋」と「髙橋」、「山崎」と「山﨑」、みたいに複数の記法がある漢字がある。
これを「JIS第〇水準」と表現することがあるが、それってそもそもUnicodeと関連があるものなんだろうか。

JISってJIS X 0208みたいな、そもそもUnicodeと別の文字集合のこと

恥ずかしながらShift_JISとJIS第〇水準という言葉に関連があることを初めて知った。
なるほど!てっきり漢検とか常用漢字みたいな、もうちょっとカジュアル寄りな話かと思ってた。

Unicodeは世界基準の文字集合なので、世界から見ると「漢字っぽいものは全部漢字」でしかない。そうなると、世界基準でみれば中国語も日本語も大体同じなのである。
実際にUnicodeの対応表を見てみると「漢字」という広い集合はあるものの、JIS水準で言えば色んな区分が混ざっている。
なので、Unicode上で「JIS第一水準の漢字のみを許可」する場合は範囲指定で綺麗に分けられるわけではない。

UTF-8を使いながらJIS第一水準の漢字のみを許可したい

実務ではこういう場面もあると思う。2つの文字集合を参照したいとき、どうするか?

イレギュラーな方を静的データとして保持するべし

基本的に1つの文字集合を使ってシステムを構築しないといけない。
仮にUTF-8を使いながら、JISの基準も入れたい場合は「JISの基準をあらかじめ取り込んでホワイトリストを作ってしまう」というのが良い。
JisX0208Level1.php みたいな感じで専用ファイルを作って、

[
    '亜' => true,
    '唖' => true,
    '娃' => true,
    '阿' => true,
    '哀' => true,
    '愛' => true,
    // ...
]

とするのが一番簡単な実装である。
あくまでもUnicodeを維持するために、JIS X 0208の表から一部を拝借して静的データに置き換えた、ということになる。
これができるということは、Unicodeで綺麗に当てはまらない集合も、他の文字集合からとってくれば良いということがわかる。

標準的な名前のバリデーションって結局どうする?

ここまでは「JIS第一水準」など他の集合を参照できる話だったけれども、「人名」というぼんやりした境界はどうやって作っていくべきだろうか。
パッと思いつく区分は「全角文字」「人名漢字・カタカナ・ひらがな」だが、この「人名漢字」ってどう区別するのか。
まずは大まかな基準がどうなっているかを調べてみたところ、以下のようになっていた。

要件 現実的なバリデーション
単なる表示名 かなり広くUnicodeを許可
日本語氏名欄 漢字・ひらがな・カタカナ・必要な記号等
古い基幹システム連携 JIS第1・第2水準など連携先仕様
戸籍レベルの正確性 戸籍統一文字/MJ文字など専用文字集合

具体的な範囲はわからないが、結局のところデータの取り扱い方によってずいぶん変わるので「絶対にこれ」という基準はなさそう。
例えばゲームのユーザー名なら危険な文字を除いて記号なども使えるべきだし、日本語氏名なら漢字であればとりあえず良し、古い基幹システムならUTF-8じゃないかもしれないからJISに対応するもの、戸籍は正確性が必要なので、戸籍に登録できる漢字を厳密に区分する。
ということで、まずは「どんな用途に使う?」が最初に来る。

その次は、一般的な人名漢字の分け方を調べてみた。

  • ‘\p{Han}‘はどこまで?
CJK Unified Ideographs
U+4E00 ~ U+9FFF

Extension A
U+3400 ~ U+4DBF

Extension B
U+20000 ~ U+2A6DF

Extension C
U+2A700 ~ U+2B73F

Extension D
U+2B740 ~ U+2B81F

Extension E
U+2B820 ~ U+2CEAF

Extension F
U+2CEB0 ~ U+2EBEF

Extension I
U+2EBF0 ~ U+2EE5F

Extension G
U+30000 ~ U+3134F

Extension H
U+31350 ~ U+323AF

Extension J
U+323B0 ~ U+3347F

代表的な漢字系の文字体系とされる"Han"について調べてみたところ、かなり色んな範囲をカバーしていることが分かった。
だいたいの常用漢字はU+4E00 ~ U+9FFFに入っていて、それ以外は基本的に見たことがないもの。