Python for Informaticas第11章の正則表現(四)


注:以下の文章の原文はDr Chares Severanceの『Python for Informaticas』から来ています。
11.3クエリーと抽出を組み合わせる
もし私達が「X-」の文字列の先頭の行で数字を見つけたいなら、次の2行の文字列のようです。
X-DSPAM-Confidence:0.8475
X-DSPAM-Probability:0.0000
しかし、私たちは任意の行の中の任意の浮動小数点を求めるだけではなく、上の形式の行の中の数字を持っています。
以下の正規表現を作成して、このような行を選択できます。
^X-.*:[0-9.]+
この表式の意味は、「X-」の2文字の先頭に、後ろに任意の文字「*」と続いて、続いて「とスペース」「スペースの後には、1つ以上の数字または小数点「[0-9.」+」と続くということです。注意すべきは、四角い括弧の中の「.」は、どの文字にもマッチするのではなく、真の「.」にマッチするもので、四角い括弧の外の「.」と区別されます。
これは非常にコンパクトな表現で、興味のある行に非常によくマッチします。

import re
hand = open('mobx-short.txt')
for line in hand:
line = line.rstrip()
if re.search('^X-.*: [0-9.]+', line)
print(line) 
このプログラムを実行すると、私たちが欲しいデータが完璧にフィルタリングされて表示されます。
X-DSPAM-Confidence:0.8475
X-DSPAM-Probability:0.0000
X-DSPAM-Confidence:0.618
X-DSPAM-Probability:0.0000
しかし、私たちは数字を抽出する問題をスプリットを使って解決しなければなりません。しかし,この問題がsplitで解決できるほど簡単である場合,正規表現の別の特徴を用いて,逐次検索と解析機能を達成することができた。
丸括弧()は正規表現の他の特殊文字です。式に丸括弧を追加すると、文字列のマッチング過程で無視されますが、findll()を使うと、丸括弧は正則表現全体にマッチしたいと考えていますが、丸括弧内にある関心のある文字列だけを抽出します。
ですから、私たちはプログラムを次のように修正します。

import re
hand = open('mbox-short.txt')
for line in hand:
line = line.rstrip()
x = re.findall('^X-.*: ([0-9.]+)', line)
if len(x) > 0 :
print(x) 
正規表現では、マッチング浮動小数点の数字部分に括弧を追加し、search()の代わりにfindll()を使って、私たちが欲しい浮動小数点の数字部分を返します。このプログラムの出力は以下の通りです。
['0.8475']
['0.0000']
['0.618']
['0.0000']
['0.6961']
['0.0000']
..。
これらのリストの数字は文字列から浮動小数点に変換する必要がありますが、正規表現を適用して、興味のある情報を同時に検索して抽出しました。
このテクニックを使ったもう一つのケースです。ファイルを見ると、多くの行がこのようなフォーマットであることが分かります。
Detail:http://source.sakaiproject.org/viewsvn/?view=rev&rev=39772
同じ技術で修正番号を抽出したいなら、コードを作成できます。

import re
hand = open('mbox-short.txt')
for line in hand:
line = line.rstrip()
x = re.findall('^Details:.*rev=([0-9]+)', line)
if len(x) > 0 :
print(x)
私たちの正規表現は「Details:」で始まり、あとは任意の文字でもいいです。*「あとは」rev=「最後は以上の数字です。行は正規表現全体にマッチすることを希望しますが、括弧内の「0-9」+の数だけが必要です。プログラムを実行すると、以下の出力が得られます。
['39772']
['39771']
['39770']
['39769']

覚えてください。「[0-9]+」は欲張りで、可能な数字を抽出しようとします。だから、私たちが得た文字列は全部で5つの数字があります。正規表現ライブラリの行の先頭と最後の2つの方向を拡張します。数字以外の文字を数えるだけです。
私たちは正規表現で本の前の練習をやり直します。この練習では、メールの時間ごとに興味があります。私たちが探している行の書式は以下の通りです。
From [email protected] Jan 5 09:14:16 2008
そして、私たちは各行の日付の中の時間情報を抽出したいです。以前は二回の呼出しでスプリットを実現しました。初めて私たちは行を単語に分離してから、第五の単語をコロンに基づいて再度分離し、興味のある2文字を引き出します。
検索する行が良いフォーマットであると仮定すれば、少ないコードを思い付くだけで実行できます。しかし、このようなフォーマットを備えていないとプログラムに失敗し、必要なエラーチェック(またはtry/exceptブロック)を追加すると、このコードは10-15行に膨らみ、読み取りが難しいです。
下記の正規表現を使って作業を簡単にすることができます。
^From.*[0-9][0-9]:
この表式の意味は「From」の先頭(空欄に注意)で、任意の文字「*」に続いて、次はスペースで、次は2つの数字「[0-9]、[0-9]」と続くコロンです。私たちが探しているのはこのような形式の行です。
findllでは時間を表す2桁の数字だけを抽出するために、式を次のように修正します。
^From.*([0-9][0-9]):
最後のこのプログラムはこうです。

import re
hand = open('mbox-short.txt')
for line in hand:
line = line.rstrip()
x = re.findall('ˆFrom .* ([0-9][0-9]):', line)
if len(x) > 0 : 
print(x)
プログラム運転の結果は以下の通りです。
['09']
['18']
['16']
['15']

関連記事:
Python for Informaticas第11章正則表現(一)
Python for Informaticas第11章の正則表現(2)
Python for Informaticas第11章の正則表現(四)について、ここに紹介します。ご協力をお願いします。引き続き更新しますので、もっと素晴らしい内容になりますので、ご注意ください。