正規表現での漢字マッチをUnicodeプロパティーを使って綺麗に書く方法 in Python

Unicode暗記してますか?

日本語で自然言語処理をやったことがある人なら誰もが一度はぶつかるであろう問題が、特定の文字種だけを抜き出す処理だと思います。
「python 正規表現 漢字」などで検索すると

re.serach([-んア-ン一-])

こんな感じの正規表現がよく見付かると思います。あ-んア-ンはまあいいとして一-鿐これ本当に正しいんでしょうか?別のサイトでは[一-龠]と書いてあったりして、よく分かりません。
そもそもこの形式の範囲指定でいいんでしょうか?つまりユニコードで本当に全ての漢字が一塊に配置されているんでしょうか?1
答えはノーで、この形式では漢字を取り零すか、漢字以外のものも含むかしかありません。(参考)

Unicode Script

そこでUnicode scriptの登場です。これはUnicode側の定義で文字種などを定義しているものになります。\p{Ascii}\p{Katakana}などがあります。
なんかBlockとかPropertyとかSciptとか色々あって、厳密には違うみたいなんですが、調べてる+書いてる時間がないので、本記事ではScriptでいきます。
python以外の言語で漢字の正規表現方法を調べると、これを使った用例がいっぱい出てくると思います。

regexモジュール

ところがpythonの正規表現モジュールreは、Unicode Scriptは使えません。
が、regexという、reの代替を狙ったモジュールがあり、こちらはUnicode Scriptに対応しています。

>>> import regex
>>> regex.findall(r'\p{Han}+',"朝早く起きた")
['朝早', '起']

このように、漢字だけにマッチしていることが分かります。

>>> print(regex.findall(r'[あ-んア-ン一-鿐]',"々"))
[]
>>> regex.findall(r'\p{Han}+',"々")
['々']

Unicode Scriptだけで拾える場合もあります。

漢字以外にもScriptによる文字種指定を使おう

気付いた人もいると思いますが、最初に出てきた[あ-ん]は間違いです2。「ぁ」に引っ掛りません。片仮名も同様でかなり深刻ですよね。漢字だけでなく、平仮名、片仮名でも文字種で指定した方が安全ですね。

>>> regex.findall(r'\p{Katakana}+',"ファンターを飲んだ")
['ファンタ']
>>> regex.findall(r'\p{Hiragana}+',"ファンターを飲んだ")
['を', 'んだ']

ただし、延ばし棒が記号扱いで、拾えなかったりするので、そこは適宜補う必要があります3

皆さんも是非、正規表現を使いこなして、楽しく日本語自然言語処理をしましょう。


  1. こういう範囲指定って、C言語でAsciiだけ扱ってたころの匂いを感じるのは私だけでしょうか? 

  2. 見に行ったページに書いてあったので、あえてそのまま載せてます。 

  3. 確か\p{S}とかで記号が拾えたような…(駄目みたいです。scivolaさんご指摘ありがとうございます。)