phpで漢字の正規表現を調べる(utf-8)

※この記事は異体字セレクタが考慮されていません。
[phpでの漢字の正規表現を調べる](http://qiita.com/awm-kaeruko/items/56198f98968050e5e2a5)をご参照ください。

Unicodeで「漢字」の正規表現
http://tama-san.com/?p=196
このページを参考にさせて頂きました。

結論から言うと

```php
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)](http://unicode.org/cldr/utility/character.jsp?a=2ee4)とか[⻨(U+2EE8)](http://unicode.org/cldr/utility/character.jsp?a=2ee8)とかも入ってますが、
常用漢字の[鬼(U+9B3C)](http://unicode.org/cldr/utility/character.jsp?a=9b3c)や[麦(U+9EA6)](http://unicode.org/cldr/utility/character.jsp?a=9ea6)とは別の字です。

なお、抜かした[U+2E9A](http://unicode.org/cldr/utility/character.jsp?a=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まで指定します。

## ここまで考慮したすべての正規表現

これで日本語の漢字にマッチさせる正規表現が出来ました。

```php
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にします。

```php
$hoge = コードポイント;
mb_convert_encoding(pack( "N", $hoge ) , "UTF-8", "UCS-4");
```

他にも、こんな方法があるようです。

```php
$hoge = コードポイント;
json_decode('"\u'.dechex($hoge).'"');
```

http://stackoverflow.com/questions/17539412/print-unicode-characters-php


# 参考資料
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