「ポ」と「ポ」は違う文字なのでgrepにヒットしない話

見た目が同じ文字でもgrepにヒットしない場合があるという話
kanata8ヶ月前に追加

こういう事象になる

$ cat popopo.txt
ポポポポーン1
ポポポポーン2
$ grep "ポ" popopo.txt
ポポポポーン1
$ grep "ポ" popopo.txt
ポポポポーン2

おわかり頂けただろうか…
「ポ」をgrepしてもどちらかしかヒットしない

なぜか…

Unicode結合文字という仕様がある

「ポ」と「ポ」は、見た目が同じですが実は違う形式でできているから(Unicodeの仕様)
見た目は同じですが、コンピュータ上では別の文字として扱われます
なので、grepにヒットしない「ポ」がでてきます

「ポ」   と       「ポ」
U+30DD       「ホ」 +「゚」
             U+30DB   U+309A

これは濁音(「が」とか)と半濁音(「プ」とか)のすべての文字に当てはまります

Unicode正規化という対応方法がある

えぇ…じゃぁすごい困るじゃん…検索できないじゃん…
ってなるので、Unicode正規化と呼ばれる統一する方法があります
任意のプログラム言語で実装もできるのですが、ワンライナーでも変換できます

pythonを使ったワンライナー

echo -n "DQⅢ①⑳海海神神㌔㍉ビデブー" | python -c "import sys,unicodedata; print(unicodedata.normalize(\"NFKC\", sys.stdin.read()));"
DQIII120海海神神キロミリビデブー

perlを使ったワンライナー

echo -n "DQⅢ①⑳海海神神㌔㍉ビデブー" | perl -e "use strict;use utf8;use Encode;use Unicode::Normalize;binmode STDIN, ':encoding(UTF-8)';binmode STDOUT, ':encoding(UTF-8)';print Unicode::Normalize::NFKC(<STDIN>);"
DQIII120海海神神キロミリビデブー

※"DQⅢ①⑳海海神神㌔㍉ビデブー"はテストデータです

では、冒頭の「ポ」で試してみます

$ cat popopo.txt | python -c "import sys,unicodedata; print(unicodedata.normalize(\"NFKC\", sys.stdin.read()));" | grep "ポ"
ポポポポーン1
ポポポポーン2

うまくいきました

参考

Unicode結合文字 難読化シェル芸
https://www.slideshare.net/kanata1/unicode-112630484

この仕様で遊んでた時の話

文字コードのカオスな世界を整理してみた
https://raintrees.net/news/51

そもそもの文字コードの話


コメント

クリップボードから画像を追加 (サイズの上限: 100 MB)