LoginSignup
2
3

More than 3 years have passed since last update.

言語処理100本ノック-22:カテゴリ名の抽出

Posted at

言語処理100本ノック 2015「第3章: 正規表現」22本目「カテゴリ名の抽出」記録です。
今回はキャプチャ対象外・非貪欲マッチを使います。少しずつ覚える内容が出てくるのがこの100本ノックのいい点ですね。

参考リンク

リンク 備考
022.カテゴリ名の抽出.ipynb 回答プログラムのGitHubリンク
素人の言語処理100本ノック:22 多くのソース部分のコピペ元
ゼロから覚えるPython正規表現の基本とTips 当ノックで学習した内容を整理しました
正規表現 HOWTO Python公式の正規表現How To
re --- 正規表現操作 Python公式のreパッケージ説明
Help:早見表 Wikipediaの代表的なマークアップの早見表

環境

種類 バージョン 内容
OS Ubuntu18.04.01 LTS 仮想で動かしています
pyenv 1.2.15 複数Python環境を使うことがあるのでpyenv使っています
Python 3.6.9 pyenv上でpython3.6.9を使っています
3.7や3.8系を使っていないことに深い理由はありません
パッケージはvenvを使って管理しています

上記環境で、以下のPython追加パッケージを使っています。通常のpipでインストールするだけです。

種類 バージョン
pandas 0.25.3

第3章: 正規表現

学習内容

Wikipediaのページのマークアップ記述に正規表現を適用することで,様々な情報・知識を取り出します.

正規表現, JSON, Wikipedia, InfoBox, ウェブサービス

ノック内容

Wikipediaの記事を以下のフォーマットで書き出したファイルjawiki-country.json.gzがある.

  • 1行に1記事の情報がJSON形式で格納される
  • 各行には記事名が"title"キーに,記事本文が"text"キーの辞書オブジェクトに格納され,そのオブジェクトがJSON形式で書き出される
  • ファイル全体はgzipで圧縮される

以下の処理を行うプログラムを作成せよ.

22. カテゴリ名の抽出

記事のカテゴリ名を(行単位ではなく名前で)抽出せよ.

課題補足(「カテゴリ」について)

Help:早見表によると「カテゴリ」は[[Category:ヘルプ|はやみひよう]]形式です。この形式での「ヘルプ」部分を抽出します。
ファイル内では「カテゴリ」部分は以下のデータです。

ファイル内の「カテゴリ」部分抜粋
[[Category:イギリス|*]]\n'
[[Category:英連邦王国|*]]\n'
[[Category:G8加盟国]]\n'
[[Category:欧州連合加盟国]]\n'
[[Category:海洋国家]]\n'
[[Category:君主国]]\n'
[[Category:島国|くれいとふりてん]]\n'
[[Category:1801年に設立された州・地域]]'

回答

回答プログラム 022.カテゴリ名の抽出.ipynb

import re

import pandas as pd

def extract_by_title(title):
    df_wiki = pd.read_json('jawiki-country.json', lines=True)
    return df_wiki[(df_wiki['title'] == title)]['text'].values[0]

wiki_body = extract_by_title('イギリス')

# rを先頭にするとraw string でエスケープシーケンス無視
# 3重クォートで途中改行無視
# re.VERBOSEオプションを使うことによって、空白とコメント無視
# re.MULTILINEで複数行に対して検索
# 非貪欲マッチにすることで、短い文字列を検索
print(re.findall(r'''
                  ^                  # 文字列の先頭(なくても結果は変わらないが入れておく)
                  \[\[Category:      # 検索語句(\はエスケープ処理)
                  (                  # キャプチャ対象グループ化開始
                  .*?                # 任意の文字列0文字以上を非貪欲マッチ
                  )                  # キャプチャ対象グループ化終了
                  (?:                # キャプチャ対象外グループ化開始
                  \|                 # 検索語句'|'
                  .*                 # 任意の文字列0文字以上
                  )?                 # キャプチャ対象外グループ化終了(0/1回出現対象)
                  \]\]               # 検索語句(\はエスケープ処理)
                  $                  # 文字列の末尾(なくても結果は変わらないが入れておく)
                  ''', wiki_body, re.MULTILINE+re.VERBOSE))

回答解説

今回のメインは以下の部分です。

print(re.findall(r'''
                  ^                  # 文字列の先頭(なくても結果は変わらないが入れておく)
                  \[\[Category:      # 検索語句(\はエスケープ処理)
                  (                  # キャプチャ対象グループ化開始
                  .*?                # 任意の文字列0文字以上を非貪欲マッチ
                  )                  # キャプチャ対象グループ化終了
                  (?:                # キャプチャ対象外グループ化開始
                  \|                 # 検索語句'|'
                  .*                 # 任意の文字列0文字以上
                  )?                 # キャプチャ対象外グループ化終了(0/1回出現対象)
                  \]\]               # 検索語句(\はエスケープ処理)
                  $                  # 文字列の末尾(なくても結果は変わらないが入れておく)
                  ''', wiki_body, re.MULTILINE+re.VERBOSE))

?:...でキャプチャ対象外

(?:...)をつけると検索結果文字列に含めずキャプチャ対象外となります。
今回は[[Category:ヘルプ|はやみひよう]]形式の|はやみひょう部分は取得したくないのでキャプチャ対象外としています。
以下の例では、4の部分を正規表現パターンとはしていますが、結果には出力していません。

>>> re.findall(r'(.012)(?:4)', 'A0123 B0124 C0123')
['B012']

貪欲・非貪欲マッチ

検索結果対象文字列の長さをコントロールすることができます。最大限の長さでマッチさせるのが貪欲マッチ(greedy match)で最小限の長さでマッチさせるのが非貪欲マッチ(non-greedy match)です。デフォルトは貪欲マッチです。
今回は[[Category:ヘルプ|はやみひよう]]形式で|はやみひようの部分を0/1回出現にしているので、非貪欲マッチにしないと、0回として|はやみひよう]]まで取得してしまいます。

# 貪欲マッチ
>>> print(re.findall(r'.0.*2',  'A0123 B0123'))
['A0123 B012']

# 非貪欲マッチ(*の後に?)
>>> print(re.findall(r'.0.*?2', 'A0123 B0123'))
['A012', 'B012']

出力結果(実行結果)

プログラム実行すると以下の結果が出力されます。

出力結果
['イギリス', '英連邦王国', 'G8加盟国', '欧州連合加盟国', '海洋国家', '君主国', '島国', '1801年に設立された州・地域']
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3