2018年03月06日

言語処理100本ノックでPython入門 #21 - 正規表現のmatch / ジェネレータ

  

言語処理100本ノック 2015の問題21を解きます。

■ 問題


問題20で作成したファイルを入力として、以下の問題を解きます。

21. カテゴリ名を含む行を抽出
記事中でカテゴリ名を宣言している行を抽出せよ.


カテゴリの行を抜粋してみると、以下のようになっています。これを正規表現を使って抜き出せば良いんですね。

[[Category:イギリス|*]]
[[Category:英連邦王国|*]]
[[Category:G8加盟国]]
[[Category:欧州連合加盟国]]
[[Category:海洋国家]]
[[Category:君主国]]
[[Category:島国|くれいとふりてん]]
[[Category:1801年に設立された州・地域]]
 


■ Pythonのコード
import json
import re

def readArticle(filename): with open(filename, 'r', encoding='utf8') as fin: return fin.read()
def getCategories(article): for s in article.split('\n'): if re.match(r'\[\[Category:.*\]\]', s): yield s
def main(): # england-article.txtは、問題20(nlp20.py)で作成したファイル article = readArticle('england-article.txt') for cat in getCategories(article): print(cat)
if __name__ == '__main__': main()

■ 今回のトピックなど

split関数 

問題20で作成したテキストファイルを入力にしています。 このテキストファイルをread()で一気に読み込んでいるので、行単位に分けるのに、 以下のようにsplit関数を使っています。
for s in text.split('\n'):

これで行単位に分割して、ループさせます。 r

e.search/re.match

カテゴリ名を宣言している行を抽出するには、searchメソッドを使えばOKですね。

なお、この2つの関数はmatchオブジェクトを返しますが、このmatchオブジェクトは常にブール値 True を持つらしいです。
オブジェクトがブール値を持つってC#プログラマとしてはちょっと違和感がありますが、まあ、便利なので良しとします。

で、見つからなかったときは、Noneを返すので、if文使ってマッチしたかどうかを調べられるようになっています。
if re.search(r'\[\[Category:.*\]\]', s):

これで、Categoryの行を取り出しています。

if re.match(r'\[\[Category:.*\]\]', s):
でも良いみたいです。

matchは行頭から一致するかを調べる。一方、searchは、指定パターンが文字列に含まれていればよいです。 ここでは、matchを使いました。

C#と違うから、なんか間違えそうです。

ちなみに、
r'\[\[Category:.*\]\]'
は、C#で書くと、
@"\[\[Category:.*\]\]"
と同じです。


ジェネレータ(generator)

pythonでも、yieldが使えます。 getCategories関数は、yieldで列挙してるから、以下のようにfor文で取り出せます。うれしい機能ですね。
for cat in getCategories(article):
    print(cat)

■ 結果
[[Category:イギリス|*]]
[[Category:英連邦王国|*]]
[[Category:G8加盟国]]
[[Category:欧州連合加盟国]]
[[Category:海洋国家]]
[[Category:君主国]]
[[Category:島国|くれいとふりてん]]
[[Category:1801年に設立された州・地域]]