※この記事は異体字セレクタが考慮されていません。
phpでの漢字の正規表現を調べるをご参照ください。
Unicodeで「漢字」の正規表現
http://tama-san.com/?p=196
このページを参考にさせて頂きました。
結論から言うと
preg_match("/([\x{3005}\x{3007}\x{303b}\x{3400}-\x{9FFF}\x{F900}-\x{FAFF}\x{20000}-\x{2FFFF}])(.*|)/u", $hoge, $matches);
となります。
以下経緯
phpで文字が漢字かチェックするとき
[一-龠]
という正規表現を使っていたのですが、
これだと繰り返し記号[々]が入ってないことがわかって、
他にも取りこぼしがないか調べてみました。
Unicodeの漢字の範囲はどこからどこまで?
unicodeの公式サイトでInput欄に\p{Han}を入れて検索すると
http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5Cp%7BHan%7D&ucd=on
漢字の一覧が出てきます。
これを上から順に日本語の漢字の範囲を拾ってきます。
CJK Radicals Supplement
最初のセクションは
CJK Radicals Supplementという分類の
2E80 ;CJK RADICAL REPEAT 〜 2EF3 ;CJK RADICAL C-SIMPLIFIED TURTLE
⺀ (繰り返し)から始まって2E9Aを抜かして⻳まで。
一覧にすると
⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳
となります。
見た感じ、書いたことも読んだこともないような文字が並んでいますね。
Unicodeの漢字はCJK統合漢字と言って
中国、日本、韓国で使われている漢字がごちゃまぜに入っているのです。
⻤(U+2EE4)とか⻨(U+2EE8)とかも入ってますが、
常用漢字の鬼(U+9B3C)や麦(U+9EA6)とは別の字です。
なお、抜かしたU+2E9Aは欠番っぽいです。
Kangxi radicals
お次のセクションは
Kangxi radicalsという分類。
2F00 ;KANGXI RADICAL ONE 〜 2FD5 ;KANGXI RADICAL FLUTE
⼀⼁⼂⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌⼍⼎⼏⼐⼑⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜⼝⼞⼟⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿⽀⽁⽂⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿⾀⾁⾂⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌⾍⾎⾏⾐⾑⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜⾝⾞⾟⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿⿀⿁⿂⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌⿍⿎⿏⿐⿑⿒⿓⿔⿕
部首の一覧らしいです。いらないですね。
CJK symbols and punctuation
3005 ;IDEOGRAPHIC ITERATION MARK
3007 ;IDEOGRAPHIC NUMBER ZERO
このセクションは々(反復記号)と〇(0)です。
〇はともかく々は使うので漢字の範囲に含めます。
HANGZHOU NUMERAL
3021 ;HANGZHOU NUMERAL ONE 〜 303A ;HANGZHOU NUMERAL THIRTY
蘇州号碼とかいう数字らしいです。含めません。
Other CJK punctuation
303B ;VERTICAL IDEOGRAPHIC ITERATION MARK
〻(反復記号)です。古文とかで出てくるので含めます。
CJK Unified Ideographs Extension A
3400..4DB5 ;CJK UNIFIED IDEOGRAPH-4DB5
CJK統合漢字拡張Aというもので、
主として地名や人名などに用いられる漢字が含まれているらしいです。含めます。
CJK Unified Ideographs
4E00..9FCC ;CJK UNIFIED IDEOGRAPH-9FCC
CJK統合漢字。日本語の漢字も含まれています。
冒頭で書いた[一-龠]がこの範囲ですね。一は4E00、龠は9FA0に当たります。
(ちなみに龠は「やく」で変換出来ます。中国の笛らしい。)
無視されてる9FA0から9FCCまでは
龡龢龣龤龥龦龧龨龩龪龫龬龭龮龯龰龱龲龳龴龵龶龷龸龹龺龻龼龽龾龿鿀鿁鿂鿃鿄鿅鿆鿇鿈鿉鿊鿋鿌
という漢字が並んでいます。
このセクションは4E00から9FFFまで領域が割り当てられており、
Unicodeがアップデートすると増えていく可能性があるので、9FFFまで指定します。
CJK Compatibility Ideographs
F900 ;CJK COMPATIBILITY IDEOGRAPH-F900 〜 FAD9 ;CJK COMPATIBILITY IDEOGRAPH-FAD9
CJK互換漢字。本来CJK統合漢字に統合されるはずなのに既存の文字コードとの互換性のためUnicodeに収録されてしまったらしいです。
日本で使うのは以下だけみたいだけど、実際どうなんだろう。
U+FA0E 〜 U+FA2D
IBM拡張漢字のうち、CJK統合漢字のブロックに収録されなかったもの。IRGを経由する漢字の通常の登録提案を経ずに、カナダからの提案としてISO/IEC 10646に収録されたため、「カナダ漢字」と呼ばれることがある
FA30 〜 FA6A
日本の文字コード規格JIS X 0213において人名許容・康煕別掲と呼ばれる漢字の一群と互換性を確保するために収録されたもの。
FA6B 〜 FA6D
日本のデータ放送規格ARIB STD-B24で使われる文字コードに収録されている独自の漢字(ARIB外字)のうち、既存の漢字に包摂されていると考えられるもの
CJK互換漢字はFAFFまで領域が割り当てられているので、Unicodeのバージョンアップを考えてFAFFまで指定します。
CJK Unified Ideographs Extension B
20000..2A6D6 ;CJK UNIFIED IDEOGRAPH-2A6D6
CJK統合漢字拡張B。JIS X 0213に一部対応しており、地名や人名などに用いられる漢字が含まれている。含めます。
CJK Unified Ideographs Extension C~F
これについては日本語の漢字であるという情報が見つからないのですが、
CJKのコードであるので一応含めておきます。
残りの拡張文字と、将来的に追加される漢字に対応するため2FFFまで指定します。
ここまで考慮したすべての正規表現
これで日本語の漢字にマッチさせる正規表現が出来ました。
preg_match("/([\x{3005}\x{3007}\x{303b}\x{3400}-\x{9FFF}\x{F900}-\x{FAFF}\x{20000}-\x{2FFFF}])(.*|)/u", $hoge, $matches);
Unicodeを文字に変換する
ところで、この正規表現に出てくるUnicodeの番号(コードポイント)ってどうやって文字に変換するのでしょうか。
一度コードポイントをバイナリに変換し、mb_convert_encodingでUTF-8にします。
$hoge = コードポイント;
mb_convert_encoding(pack( "N", $hoge ) , "UTF-8", "UCS-4");
他にも、こんな方法があるようです。
$hoge = コードポイント;
json_decode('"\u'.dechex($hoge).'"');
参考資料
UTF-8の漢字の正規表現は[一-龠々]?
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1229555292
Unicodeで「漢字」の正規表現
http://tama-san.com/?p=196
UTF-8 と UCS-4 の変換を php で行う場合の例
http://insnvlovn.blogspot.jp/2010/03/utf-8-ucs-4-php.html
CJK互換漢字
http://ja.wikipedia.org/wiki/CJK%E4%BA%92%E6%8F%9B%E6%BC%A2%E5%AD%97