PHP で漢字(かんじ)のバリデーションを作る

目次

結論

簡易的には、PCRE 関数 の preg_match を利用して正規表現のマッチングによるバリデーションを実装します。

第一引数の pattern には、PCRE 正規表現構文 の Unicode 文字プロパティ である\p{Han}を指定します。

function checkKanji(string $str): int|false {
  return preg_match("/\A\p{Han}+\z/u", $str);
}

マッチする範囲は下記になります。

  1. (U+2E80) – (U+2EF3) : CJK Radicals Supplement
  2. (U+2F00) – (U+2FD5) : Kangxi Radicals
  3. (U+3005) – (U+3007), (U+3021) – (U+3029), (U+3037) – (U+303F) : CJK Symbols and Punctuation
  4. (U+3400) – U+4DBF : CJK Unified Ideographs Extension A
  5. (U+F900) – U+FAD9 : CJK Compatibility Ideographs
  6. U+16FE2, U+16FE3, U+16FF0, U+16FF1 : Ideographic Symbols and Punctuation
  7. U+20000 – U+2A6DF : CJK Unified Ideographs Extension B
  8. U+2A700 – U+2B738 : CJK Unified Ideographs Extension C(U+2B739 を除く)
  9. U+2B740 – U+2B81D : CJK Unified Ideographs Extension D
  10. U+2B820 – U+2CEA1 : CJK Unified Ideographs Extension E
  11. U+2CEB0 – U+2EBE0 : CJK Unified Ideographs Extension F
  12. U+2F800 – U+2FA1D : CJK Compatibility Ideographs Supplement
  13. U+30000 – U+3134A : CJK Unified Ideographs Extension G

文字で範囲を指定する場合、例えば、CJK Radicals Supplement + Kangxi Radicals は下記のようになります。

function checkKanji(string $str): int|false {
  return preg_match("/\A[⺀-⻳⼀-⿕]+\z/u", $str);
}

マッチする範囲は下記になります。

  1. (U+2E80) – (U+2EF3) : CJK Radicals Supplement
  2. (U+2F00) – (U+2FD5) : Kangxi Radicals

下記のように Code point(コードポイント)で範囲を指定することも可能です。

function checkKanji(string $str): int|false {
  return preg_match("/\A[\x{2E80}-\x{2EF3}\x{2F00}-\x{2FD5}]+\z/u", $str);
}

マッチさせる範囲は、要件に合わせて pattern を書き換えると良いでしょう。

例えば、地名や人名漢字を含めたい場合は CJK Compatibility IdeographsCJK Unified Ideographs Extension A を含める等の対応が必要になります。

環境

  1. MAMP 6.8
  2. Apache 2.4.54
  3. PHP 8.2.0

解説

初めに、Unicode Block を理解しましょう。

Unicode とは、簡単に言うと Unicode Consortium という非営利団体によって維持されている世界中の文字や記号を 1 つの文字コード体系で扱える様に作られた符号化文字集合のことです。

Unicode Block とは、Code point の連続する範囲のことです。

Code point とは、特定の文字にマップされる数値のことです。

例えば、Unicode は 0 hex – 10FFFF hex の数値です。

仕様

漢字が含まれる Unicode Block は下記になります。

  1. CJK Radicals Supplement(CJK 部首補助)
  2. Kangxi Radicals(康煕部首)
  3. CJK Symbols and Punctuation(CJK の記号及び句読点)
  4. CJK Unified Ideographs Extension A(CJK 統合漢字拡張 A)
  5. CJK Compatibility Ideographs(CJK 互換漢字)
  6. Ideographic Symbols and Punctuation(表意文字の記号及び句読点)
  7. CJK Unified Ideographs Extension B(CJK 統合漢字拡張 B)
  8. CJK Unified Ideographs Extension C(CJK 統合漢字拡張 C)
  9. CJK Unified Ideographs Extension D(CJK 統合漢字拡張 D)
  10. CJK Unified Ideographs Extension E(CJK 統合漢字拡張 E)
  11. CJK Unified Ideographs Extension F(CJK 統合漢字拡張 F)
  12. CJK Unified Ideographs Extension I(CJK 統合漢字拡張 I)
  13. CJK Compatibility Ideographs Supplement(CJK 互換漢字補助)
  14. CJK Unified Ideographs Extension G(CJK 統合漢字拡張 G)
  15. CJK Unified Ideographs Extension H(CJK 統合漢字拡張 H)

実装

PCRE 関数 の preg_match を利用して正規表現のマッチングによるバリデーションを実装します。

第一引数の pattern には、PCRE 正規表現構文 の Unicode 文字プロパティ である\p{Han}を指定します。

function checkKanji(string $str): int|false {
  return preg_match("/\A\p{Han}+\z/u", $str);
}

記述している PCRE 正規表現構文 の説明になります。

  1. /デリミタ
  2. \Aエスケープシーケンス 検索対象文字列の始端
  3. \p{Han} : マッチする範囲は下記になります。
    1. (U+2E80) – (U+2EF3) : CJK Radicals Supplement
    2. (U+2F00) – (U+2FD5) : Kangxi Radicals
    3. (U+3005) – (U+3007), (U+3021) – (U+3029), (U+3037) – (U+303F) : CJK Symbols and Punctuation
    4. (U+3400) – U+4DBF : CJK Unified Ideographs Extension A
    5. (U+F900) – U+FAD9 : CJK Compatibility Ideographs
    6. U+16FE2, U+16FE3, U+16FF0, U+16FF1 : Ideographic Symbols and Punctuation
    7. U+20000 – U+2A6DF : CJK Unified Ideographs Extension B
    8. U+2A700 – U+2B738 : CJK Unified Ideographs Extension C
    9. U+2B740 – U+2B81D : CJK Unified Ideographs Extension D
    10. U+2B820 – U+2CEA1 : CJK Unified Ideographs Extension E
    11. U+2CEB0 – U+2EBE0 : CJK Unified Ideographs Extension F
    12. U+2F800 – U+2FA1D : CJK Compatibility Ideographs Supplement
    13. U+30000 – U+3134A : CJK Unified Ideographs Extension G
  4. +量指定子 {1,} と同じ 直前の表現を 1 回以上繰り返す
  5. \zエスケープシーケンス 検索対象文字列の終端
  6. u修飾子 UTF-8 として処理する

文字で範囲を指定する場合、例えば、CJK Radicals Supplement + Kangxi Radicals は下記のようになります。

function checkKanji(string $str): int|false {
  return preg_match("/\A[⺀-⻳⼀-⿕]+\z/u", $str);
}

記述している PCRE 正規表現構文 の説明になります。

  1. /デリミタ
  2. \Aエスケープシーケンス 検索対象文字列の始端
  3. []文字クラス
  4. (U+2E80) – (U+2EF3) : CJK Radicals Supplement
  5. (U+2F00) – (U+2FD5) : Kangxi Radicals
  6. +量指定子 {1,} と同じ 直前の表現を 1 回以上繰り返す
  7. \zエスケープシーケンス 検索対象文字列の終端
  8. u修飾子 UTF-8 として処理する

マッチさせる範囲は、要件に合わせて pattern を書き換えると良いでしょう。

下記のように Code point(コードポイント)で範囲を指定することも可能です。

function checkKanji(string $str): int|false {
  return preg_match("/\A[\x{2E80}-\x{2EF3}\x{2F00}-\x{2FD5}]+\z/u", $str);
}
  1. /デリミタ
  2. \Aエスケープシーケンス 検索対象文字列の始端
  3. []文字クラス
  4. \x{...} : 0 ~ 4 桁の 16進数で Unicode 文字指定
  5. {2E80}{2EF3} : CJK Radicals Supplement
  6. {2F00}{2FD5} : Kangxi Radicals
  7. +量指定子 {1,} と同じ 直前の表現を 1 回以上繰り返す
  8. \zエスケープシーケンス 検索対象文字列の終端
  9. u修飾子 UTF-8 として処理する

マッチさせる範囲は、要件に合わせて pattern を書き換えると良いでしょう。

検証

検証用に簡単なプログラムを書きました。

<?php
$kanji = $_POST['kanji'] ?? '';
$kanji_2 = $_POST['kanji2'] ?? '';
$kanji_3 = $_POST['kanji3'] ?? '';

if ($kanji) {

  if (checkKanji($kanji)) echo '<p>漢字(Unicode 文字プロパティ)の入力チェック結果 : OK</p>';
  else echo '<p>漢字(Unicode 文字プロパティ)の入力チェック結果 : NG</p>';
}

if ($kanji_2) {

  if (checkKanji2($kanji_2)) echo '<p>漢字(文字)の入力チェック結果 : OK</p>';
  else echo '<p>漢字(文字)の入力チェック結果 : NG</p>';
}

if ($kanji_3) {

  if (checkKanji3($kanji_3)) echo '<p>漢字(コードポイント)の入力チェック結果 : OK</p>';
  else echo '<p>漢字(コードポイント)の入力チェック結果 : NG</p>';
}

function checkKanji(string $str): int|false {
  return preg_match("/\A\p{Han}+\z/u", $str);
}

function checkKanji2(string $str): int|false {
  return preg_match("/\A[⺀-⻳⼀-⿕]+\z/u", $str);
}

function checkKanji3(string $str): int|false {
  return preg_match("/\A[\x{2E80}-\x{2EF3}\x{2F00}-\x{2FD5}]+\z/u", $str);
}

?>

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
</head>
<body>

<hr>
<form method="post">
  <p>
    漢字(Unicode 文字プロパティ):<input type="text" name="kanji">
  </p>
  <p>
    漢字(文字):<input type="text" name="kanji2">
  </p>
  <p>
    漢字(コードポイント):<input type="text" name="kanji3">
  </p>
  <input type="submit" value="送信する">
</form>

</body>
</html>

漢字(Unicode 文字プロパティ)

下記の文字列とマッチします。

⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳
⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕
々〆〇〡〢〣〤〥〦〧〨〩〷〸〹〺〻〼〽〾〿㐀䶿豈龎

漢字(文字)

下記の文字列とマッチします。

⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳
⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕

漢字(コードポイント)

下記の文字列とマッチします。

⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳
⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕

参考

  1. PHP マニュアル
  2. Unicode block
目次