PHPのmb_convert_kanaとUnicodeのNFKC正規化

アルファベットや仮名などの文字列に対して検索などの目的で全角半角統一などの正規化をしたい場合に、 PHPでは mb_convert_kana を使うことがある。同じ目的でJavaなどではUnicodeのNFKC正規化を使うことがある。

NFKC正規化では大雑把にいうと、半角カナは全角カタカナに変換され、全角の英数字や記号は半角に変換される。これはなんとなくPHPの mb_convert_kana($str, 'asKV', 'UTF-8') と同じになりそうな気がするのであるが、厳密に同じになるわけではない。その違いを調べてみた。

mb_convert_kana の2つ目の引数はどんな変換をするかを表し、以下の意味がある。

a
全角英数字を半角に
s
全角スペース(U+3000)を半角(U+0020)に
K
半角カタカナを全角カタカナに
V
半角カタカナの濁点を全角カタカナに変換する際に前の文字と結合する

mb_convert_kana 関数 | PHP Manual
http://php.net/manual/ja/function.mb-convert-kana.php

NFKC正規化と mb_convert_kana($str, 'asKV', 'UTF-8') でいくつかの文字をサンプル的に調べたところ、以下のとおりであった。

以下は実行例。

英数字の全角半角に関して

$str = "AaAa11\n";
echo $str;
// 出力結果をUnicodeコードポイントで表すと
// 0041 0061 FF21 FF41 0031 FF11
// これをUnicode NFKC正規化すると
// 0041 0061 0041 0061 0031 0031

echo mb_convert_kana($str, 'asKV', 'UTF-8');
// 出力結果をUnicodeコードポイントで表すと
// 0041 0061 0041 0061 0031 0031
// これはUnicode NFKC正規化と一致する

丸付き数字に関して

$str = "①➀㉑\n";
echo $str;
// 出力結果をUnicodeコードポイントで表すと
// 2460 2780 3251
// これをUnicode NFKC正規化すると
// 0031 2780 0032 0031

echo mb_convert_kana($str, 'asKV', 'UTF-8');
// 出力結果をUnicodeコードポイントで表すと
// 2460 2780 3251
// これはなにも変換されておらず、Unicode NFKC正規化と一致しない

記号に関して

$str = "!\"#\$%&'()*+,-./:;<=>?@[\\]^_`{|}~\n";
echo $str;
// 出力結果をUnicodeコードポイントで表すと
// 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F 003A 003B 003C 003D 003E 003F 0040 005B 005C 005D 005E 005F 0060 007B 007C 007D 007E
// これをUnicode NFKC正規化しても変化しない

echo mb_convert_kana($str, 'asKV', 'UTF-8');
// 出力結果をUnicodeコードポイントで表すと
// 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F 003A 003B 003C 003D 003E 003F 0040 005B 005C 005D 005E 005F 0060 007B 007C 007D 007E
// これも変化しないので、Unicode NFKC正規化と一致する

$str = "!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~\n";
echo $str;
// 出力結果をUnicodeコードポイントで表すと
// FF01 FF02 FF03 FF04 FF05 FF06 FF07 FF08 FF09 FF0A FF0B FF0C FF0D FF0E FF0F FF1A FF1B FF1C FF1D FF1E FF1F FF20 FF3B FF3C FF3D FF3E FF3F FF40 FF5B FF5C FF5D FF5E
// これをUnicode NFKC正規化すると
// 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F 003A 003B 003C 003D 003E 003F 0040 005B 005C 005D 005E 005F 0060 007B 007C 007D 007E

echo mb_convert_kana($str, 'asKV', 'UTF-8');
// 出力結果をUnicodeコードポイントで表すと
// 0021 FF02 0023 0024 0025 0026 FF07 0028 0029 002A 002B 002C 002D 002E 002F 003A 003B 003C 003D 003E 003F 0040 005B FF3C 005D 005E 005F 0060 007B 007C 007D FF5E
// これはUnicode NFKC正規化とは違う

全角ひらがなに関して

$str = "ああ゙あ゛かががか゛\n";
echo $str;
// 出力結果をUnicodeコードポイントで表すと
// U+3042 U+3042 U+3099 U+3042 U+309B U+304B U+304C U+304B U+3099 U+304B U+309B
// これをUnicode NFKC正規化すると
// U+3042 U+3042 U+3099 U+3042 U+0020 U+3099 U+304B U+304C U+304C U+304B U+0020 U+3099

echo mb_convert_kana($str, 'asKV', 'UTF-8');
// 出力結果をUnicodeコードポイントで表すと
// U+3042 U+3042 U+3099 U+3042 U+309B U+304B U+304C U+304B U+3099 U+304B U+309B
// これはなにも変換されておらず、Unicode NFKC正規化と一致しない

半角カタカナに関して

$str = "アア゙カガ\n";
echo $str;
// 出力結果をUnicodeコードポイントで表すと
// U+FF71 U+FF71 U+FF9E U+FF76 U+FF76 U+FF9E
// これをUnicode NFKC正規化すると
// U+30A2 U+30A2 U+3099 U+30AB U+30AC

echo mb_convert_kana($str, 'asKV', 'UTF-8');
// 出力結果をUnicodeコードポイントで表すと
// U+30A2 U+30A2 U+309B U+30AB U+30AC
// これはUnicode NFKC正規化と一致しない
// さらにこれをUnicode NFKC正規化すると
// U+30A2 U+30A2 U+0020 U+3099 U+30AB U+30AC

上記実行例は PHP 5.5.3 で確認。

このサイトは筆者(hydrocul)の個人メモの集合です。すべてのページは永遠に未完成です。