言語処理100本ノック with Python【第3章】
No | 日付 | 学んだこと |
---|---|---|
20 | 4/13 | json、gzip |
21 | 4/14 | 正規表現、re、raise |
22 | 4/16 | 正規表現 |
第3章: 正規表現
20. JSONデータの読み込み
Wikipedia記事のJSONファイルを読み込み,「イギリス」に関する記事本文を表示せよ.問題21-29では,ここで抽出した記事本文に対して実行せよ.
1行に1記事の情報がJSON形式で格納されるので、2章のように1行読み込んでifで判定させる。
解法
import gzip import json fname = 'jawiki-country.json.gz' with gzip.open(fname, 'rt', encoding="utf-8_sig") as jsonfile: for line in jsonfile: l = json.loads(line) if l['title'] == 'イギリス': print(l['text']) break
以下のように内包表記を使って書こうと思ったけどエラーが出てしまって無理だった。。
44行目を参考にifではなくwhileを使用してみた。
もしPythonの内包表記に終了条件が指定できたら · GitHub
result = [json.loads(line) for line in jsonfile while json.loads(line) != 'イギリス']
json
# 基本的な使い方 import json fname = open('sample.json') print (json.load(fname))
・ファイルの入出力(ファイル ⇔ Pythonオブジェクト)
load() | JSON形式のファイルを読み込んでPythonオブジェクトへ 読み込んだJSONファイルは辞書型で保存される |
dump() | PythonオブジェクトをJSON形式でファイルに書き込み こっちは文字列型で保存される |
・オブジェクトの変換(文字列 ⇔ Pythonオブジェクト)
loads() | JSON文字列からPythonオブジェクトへ変換(デコード) |
dumps() | PythonオブジェクトからJSON文字列へ変換(エンコード) |
gzip
gzip.open(filename, mode='rb', compresslevel=9, encoding=None, errors=None, newline=None)
'rt'はread + text
13.2. gzip — gzip ファイルのサポート — Python 3.6.5 ドキュメント
gzという拡張子は見慣れなかったけど圧縮形式の一つで「GNU zip」の略らしい。
gunzipコマンドで解凍可能。
21. カテゴリ名を含む行を抽出
記事中でカテゴリ名を宣言している行を抽出せよ.
素人の言語処理100本ノック:21 - Qiita
参考のQiita記事ではraiseを使った処理を書いているけどtry-exceptとの違いがわかってないのでメモる。
import gzip import json import re fname = 'jawiki-country.json.gz' def get_UK_article(): with gzip.open(fname, 'rt') as jsonfile: for line in jsonfile: line_json = json.loads(line) if line_json['title'] == 'イギリス': return line_json['text'] raise ValueError('Not Found Article.') # 正規表現のコンパイル pattern = re.compile(r'^(.*\[\[Category:.*\]\].*)$', re.MULTILINE + re.VERBOSE) # 抽出 result = pattern.findall(get_UK_article()) for line in result: print(line) # [[Category:イギリス|*]] # [[Category:英連邦王国|*]] # [[Category:G8加盟国]] # [[Category:欧州連合加盟国]] # [[Category:海洋国家]] # [[Category:君主国]] # [[Category:島国|くれいとふりてん]] # [[Category:1801年に設立された州・地域]]
正規表現
メタ文字 | 説明 | 使用例 |
---|---|---|
. | 任意の一文字 | a.c |
^ | 文字列の先頭 | ^abc |
$ | 文字列の末尾 | abc$ |
* | 0回以上の繰り返し | ab* |
+ | 1回以上の繰り返し | ab+ |
? | 0回または1回 | ab? |
.* | 任意の文字0文字以上 | |
.*? | 任意の文字0文字以上、非貪欲マッチ | 貪欲だと後半の"l"で始まる装飾を巻き込んでしまう |
re
raise
22. カテゴリ名の抽出
記事のカテゴリ名を(行単位ではなく名前で)抽出せよ.
import gzip import json import re fname = 'jawiki-country.json.gz' def get_UK_article(): with gzip.open(fname, 'rt', encoding="utf-8_sig") as jsonfile: for line in jsonfile: line_json = json.loads(line) if line_json['title'] == 'イギリス': return line_json['text'] raise ValueError('Not Found Article.') pattern = re.compile(r'^.*\[\[Category:(.*?)(?:\|.*)?\]\].*$', re.MULTILINE + re.VERBOSE) result = pattern.findall(get_UK_article()) for line in result: print(line) # イギリス # 英連邦王国 # G8加盟国 # 欧州連合加盟国 # 海洋国家 # 君主国 # 島国 # 1801年に設立された州・地域
23. セクション構造
記事中に含まれるセクション名とそのレベル(例えば"== セクション名 =="なら1)を表示せよ.
# 23 import gzip import json import re fname = 'jawiki-country.json.gz' def get_UK_article(): with gzip.open(fname, 'rt', encoding="utf-8_sig") as jsonfile: for line in jsonfile: line_json = json.loads(line) if line_json['title'] == 'イギリス': return line_json['text'] raise ValueError('Not Found Article.') pattern = re.compile(r'^(={2,})\s*(.+?)\s*\1.*$', re.MULTILINE + re.VERBOSE) # 抽出 result = pattern.findall(get_UK_article()) # 結果表示 for line in result: level = len(line[0]) - 1 print('{indent}{sect}({level})'.format( indent='\t' * (level - 1), sect=line[1], level=level)) # 国名(1) # 歴史(1) # 地理(1) # 気候(2) # 政治(1) # 外交と軍事(1) # 地方行政区分(1) # 主要都市(2) # : # :