みなさん、ワンライナーで日本語を簡単に処理したい場合、何を使うでしょうか。
ワンライナーで言語処理といえばPerlですよね[要出展]。
Perlでは、「ひらがな」「カタカナ」「漢字」といった文字にマッチする正規表現を簡単に書くことができます。
例えば、青春→鯖鰆みたいなやつという記事では、漢字にマッチさせるのに\p{Han}
という正規表現を使っていました。
$ perl -Mutf8 -CSD -le 'print "漢" =~ m{\p{Han}} ? 1 : 0'
1
$ perl -Mutf8 -CSD -le 'print 1 if "あ" =~ m{\p{Han}} ? 1 : 0'
0
それが、Perlをアップデートしてから、この正規表現がおかしくなっていることに気づきました。
$ perl -Mutf8 -CSD -le 'print "「" =~ m{\p{Han}} ? 1 : 0'
1
なんてこった。
"「"は明らかに漢字じゃないだろう?
調べてみると、perlunicodeに以下のような記述がありました。
Prior to Perl v5.26, the single form returned the plain old Script version, but was changed because Script_Extensions gives better results.
「Perl v5.26までは単独形は昔ながらのScriptのバージョンを返していたが、Script_Extensionsにしたよ。そっちのほうがいい結果になるからね」
いい結果????
それ誰の意見よ??????
そもそもScript_Extentionsとは何か、ということでUnicodeのページを見てみると、例えばU+064B ARABIC FATHATANはアラビア文字でもシリア文字でも使われるから、\p{scx=Arabic}
でも\p{scx=Syriac}
でも(scxはScript_Extensionsの略)マッチしてくれるとうれしい、みたいな感じのようです。
ふぅん。
まあいいや。
それで、カギカッコ、つまりU+300C LEFT CORNER BRACKETについて調べてみると、Script_Extensionsは次のようになっています。
Bopomofo Hangul Han Hiragana Katakana Yi
なるほど、カギカッコは漢字やひらがなやカタカナと一緒に使われるからそれらのScript_Extensions扱い、ということのようです。
しかし、残念ながら――聡明な読者の皆様はお気づきのことでしょうが――日本語を扱う際には、「漢字+各種記号」「ひらがな+各種記号」「カタカナ+各種記号」という集合はまったく使い道がないのです。
なぜかというと、日本語文というのは「(漢字+ひらがな+カタカナ)+各種記号」という構成であって、例えば「カタカナ+各種記号」といった文章は基本的に存在しないからです。
そういうわけで、少なくとも日本語に関しては、いい結果どころかひどい結果になるのですが、\p{Katakana}
は「カタカナ+各種記号」にマッチするようになってしまった、ということです。
こんな非互換変更が入ってしまうなんて…。
仮に、ひらがなとカタカナにのみScript_Extensionsとして「-」(長音記号)が入る、ということであれば、これは明らかにいい結果になる変更なので、非互換変更であっても納得できたかもしれません。
でも、そうはならなかった。
そういうわけで、例えばひらがなのみにマッチさせたいとき、Perl v5.26以前であれば\p{Hiragana}
と書けばよかったところ、Perl v5.26以降では\p{sc=Hiragana}
と書かなければいけません。
面倒ですが、しょうがないですね。
ちなみに、例えば文章からカタカナ語を抽出したいという場合、[\p{sc=Katakana}ー]+
のようにするのが常道です。
Script_Extensionsがやりたかったこと、みたいな感じですね。
例えば、このテキスト(source.txt
とします)について実行すると、次のようになります。
$ perl -Mutf8 -CSD -nle 'print $1 while m{([\p{sc=Katakana}ー]+)}g' source.txt
ワンライナー
ワンライナー
カタカナ
マッチ
マッチ
...