banner
aying

aying

Time Flies,Have Fun!
github
bilibili
douban

正規表現

1. 例の導入#

オープンソース中国が提供する正規表現テストツール http://tool.oschina.net/regex/ を開き、マッチさせたいテキストを入力し、一般的な正規表現を選択すると、対応するマッチ結果が得られます。例えば、ここにマッチさせたいテキストを入力します:

こんにちは、私の電話番号は 010-86432100 で、メールは cqc@cuiqingcai.com、私のウェブサイトは https://cuiqingcai.com です。

この文字列には電話番号と電子メールが含まれており、次に正規表現を使ってそれを抽出してみましょう。
URL の場合、以下の正規表現を使用してマッチさせることができます:

[a-zA-z]+://[^\s]*

この正規表現を使って文字列をマッチさせると、その文字列に URL のようなテキストが含まれていれば、それが抽出されます。

この正規表現は一見すると混乱しているように見えますが、実際には特定の文法ルールが存在します。例えば、a-z は任意の小文字のアルファベットにマッチし、\s は任意の空白文字にマッチし、* は前の文字に任意の数だけマッチすることを示します。この長い正規表現は、これらのマッチルールの組み合わせです。

正規表現を書いたら、それを長い文字列に対してマッチさせて検索することができます。この文字列の中に何があっても、私たちが書いたルールに合致する限り、すべてを見つけることができます。ウェブページの場合、ウェブページのソースコードにどれだけの URL があるかを見つけたい場合は、URL をマッチさせる正規表現を使ってマッチさせればよいのです。

上記でいくつかのマッチルールについて説明しましたが、表 3-2 には一般的なマッチルールが示されています。

一般的なマッチルール

モデル説明
\wアルファベット、数字、アンダースコアにマッチ
\Wアルファベット、数字、アンダースコア以外の文字にマッチ
\s任意の空白文字にマッチし、[\t\n\r\f] と同等
\S任意の非空白文字にマッチ
\d任意の数字にマッチし、[0-9] と同等
\D任意の非数字の文字にマッチ
\A文字列の先頭にマッチ
\Z文字列の末尾にマッチし、改行が存在する場合は改行前の終了文字列までマッチ
\z文字列の末尾にマッチし、改行が存在する場合は改行文字もマッチ
\G最後のマッチが完了した位置にマッチ
\n1 つの改行文字にマッチ
\t1 つのタブ文字にマッチ
^1 行の文字列の先頭にマッチ
$1 行の文字列の末尾にマッチ
.任意の文字にマッチし、改行文字を除き、re.DOTALL フラグが指定されている場合は改行文字を含む任意の文字にマッチ
[...]一組の文字を示し、個別に列挙します。例えば [amk] は a、m または k にマッチ
[^...][] の中にない文字、例えば [^abc] は a、b、c 以外の文字にマッチ
*0 個以上の表現にマッチ
+1 個以上の表現にマッチ
?0 個または 1 個の前の正規表現で定義された部分にマッチし、非貪欲方式
{n}前の表現に正確に n 個マッチ
{n, m}前の正規表現で定義された部分に n 回から m 回マッチし、貪欲方式
ab
( )括弧内の表現にマッチし、グループを示します

2. match#

ここでは最初の一般的なマッチ方法である match を紹介します。マッチさせたい文字列と正規表現を渡すことで、この正規表現が文字列にマッチするかどうかを検出できます。

match メソッドは文字列の先頭から正規表現をマッチさせようとします。マッチすれば、マッチ成功の結果を返します。マッチしなければ、None を返します。以下はその例です:

import re

content = 'こんにちは 123 4567 世界_これは正規表現デモです'
print(len(content))
result = re.match('^こんにちは\s\d\d\d\s\d{4}\s\w{10}', content)
print(result)
print(result.group())
print(result.span())

実行結果は以下の通りです:

41
<_sre.SRE_Match object; span=(0, 25), match='こんにちは 123 4567 世界_これは'>
こんにちは 123 4567 世界_これは
(0, 25)

ここではまず文字列を宣言しました。その中には英字、空白文字、数字などが含まれています。次に、正規表現を作成します:

^こんにちは\s\d\d\d\s\d{4}\s\w{10}

これを使ってこの長い文字列をマッチさせます。最初の ^ は文字列の先頭にマッチし、つまり「こんにちは」で始まることを示します。そして \s は空白文字にマッチし、ターゲット文字列の空白をマッチさせます;\d は数字にマッチし、3 つの \d は 123 にマッチします;その後に 1 つの \s が空白にマッチします;次に 4567 がありますが、実際には 4 つの \d を使ってマッチさせることもできますが、そう書くのは面倒なので、後ろに {4} を付けて前のルールを 4 回マッチさせることを示します。つまり 4 つの数字にマッチします;その後に再び 1 つの空白文字が続き、最後に \w {10} が 10 個のアルファベットとアンダースコアにマッチします。ここで注意すべきは、実際にはターゲット文字列を完全にマッチさせていないことですが、これでもマッチは可能で、ただマッチ結果が少し短くなるだけです。

match メソッドでは、最初のパラメータに正規表現を渡し、2 番目のパラメータにマッチさせたい文字列を渡します。

出力結果を印刷すると、結果は SRE_Match オブジェクトであり、これは成功したマッチを証明します。このオブジェクトには 2 つのメソッドがあります:group メソッドはマッチした内容を出力でき、結果は「こんにちは 123 4567 世界_これは」であり、これは正規表現ルールがマッチした内容です;span メソッドはマッチの範囲を出力でき、結果は (0, 25) であり、これはマッチした結果文字列が元の文字列の中での位置範囲です。

上記の例を通じて、Python で正規表現を使ってテキストの一部をマッチさせる方法を基本的に理解しました。

マッチ対象#

先ほど、match メソッドを使ってマッチした文字列の内容を得ることができましたが、もし文字列から一部の内容を抽出したい場合はどうすればよいでしょうか?最初の例のように、テキストからメールや電話番号などの内容を抽出することです。

ここでは () 括弧を使って抽出したい部分文字列を括ります。() は実際にはサブ表現の開始と終了位置を示し、マークされた各サブ表現はそれぞれのグループに対応し、group メソッドを呼び出してグループのインデックスを渡すことで抽出結果を取得できます。以下はその例です:

import re

content = 'こんにちは 1234567 世界_これは正規表現デモです'
result = re.match('^こんにちは\s(\d+)\s世界', content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())

ここでは文字列の中の 1234567 を抽出したいので、数字部分の正規表現を () で括ります。そして group (1) を呼び出してマッチ結果を取得します。

実行結果は以下の通りです:

<_sre.SRE_Match object; span=(0, 19), match='こんにちは 1234567 世界'>
こんにちは 1234567 世界
1234567
(0, 19)

成功裏に 1234567 を取得できました。ここでは group (1) を使用しており、これは group () とは異なり、後者は完全なマッチ結果を出力し、前者は最初に () で囲まれたマッチ結果を出力します。もし正規表現の後にさらに () で囲まれた内容があれば、group (2)、group (3) などを使って取得できます。

一般的なマッチ#

先ほど書いた正規表現は実際にはかなり複雑で、空白文字が出てきたら \s でマッチし、数字が出てきたら \d でマッチするなど、作業量が非常に大きいです。実際には、そんなことをする必要は全くありません。なぜなら、万能マッチが使えるからです。それは .(ドットアスタリスク)です。ここで .(ドット)は任意の文字にマッチし(改行文字を除く)、(アスタリスク)は前の文字を無限回マッチさせることを示します。したがって、これらを組み合わせることで任意の文字をマッチさせることができます。これを使えば、個々の文字をマッチさせる必要がなくなります。

先ほどの例を続けて、正規表現を改写できます:

import re

content = 'こんにちは 123 4567 世界_これは正規表現デモです'
result = re.match('^こんにちは.*デモ$', content)
print(result)
print(result.group())
print(result.span())

ここでは中間部分をすべて省略し、.* で置き換え、最後に結末の文字列を加えればよいのです。実行結果は以下の通りです:

<_sre.SRE_Match object; span=(0, 41), match='こんにちは 123 4567 世界_これは正規表現デモです'>
こんにちは 123 4567 世界_これは正規表現デモです
(0, 41)

group メソッドはマッチした全ての文字列を出力し、つまり私たちが書いた正規表現がターゲット文字列の全内容にマッチしたことを示しています;span メソッドは (0, 41) を出力し、これは全体の文字列の長さです。

したがって、.* を使用して正規表現の記述を簡素化できます。

貪欲と非貪欲#

上記の一般的なマッチ .* を使用する際、時にはマッチした結果が私たちが望むものではないことがあります。以下の例を見てみましょう:

import re

content = 'こんにちは 1234567 世界_これは正規表現デモです'
result = re.match('^ハ.*(\d+).*デモ$', content)
print(result)
print(result.group(1))

ここでも中間の数字を取得したいので、(\d+) を書いています。しかし、数字の両側は内容が雑然としているため、省略して書くことにし、すべて .* にしてしまいました。最後に、^ ハ.*(\d+).* デモ $ という構成に見えますが、特に問題はないように見えます。実行結果を見てみましょう:

<_sre.SRE_Match object; span=(0, 40), match='こんにちは 1234567 世界_これは正規表現デモです'>
7

奇妙なことが起こりました。私たちは 7 という数字だけを得ました。これはどういうことでしょうか?

ここで貪欲マッチと非貪欲マッチの問題が関係しています。貪欲マッチでは、.* はできるだけ多くの文字にマッチします。正規表現の中で .* の後に \d+ があり、つまり少なくとも 1 つの数字にマッチしますが、具体的に何個の数字かは指定していません。したがって、.* はできるだけ多くの文字をマッチさせ、ここでは 123456 をマッチさせ、\d+ に条件を満たす数字 7 を残しました。最終的に得られた内容は数字 7 だけでした。

しかし、これは明らかに非常に不便です。時には、マッチ結果が不意に一部の内容を欠いてしまうことがあります。実際には、ここで非貪欲マッチを使用すればよいのです。非貪欲マッチの書き方は .*? で、? を追加することで、どのような効果が得られるのでしょうか?再度例を見てみましょう:

import re

content = 'こんにちは 1234567 世界_これは正規表現デモです'
result = re.match('^ハ.*?(\d+).*デモ$', content)
print(result)
print(result.group(1))

ここでは最初の .* を .*? に変更し、非貪欲マッチにしました。結果は以下の通りです:

<_sre.SRE_Match object; span=(0, 40), match='こんにちは 1234567 世界_これは正規表現デモです'>
1234567

この時、1234567 を成功裏に取得できました。理由は明らかです。貪欲マッチはできるだけ多くの文字をマッチさせ、非貪欲マッチはできるだけ少ない文字をマッチさせます。.? が「こんにちは」の後の空白文字にマッチした時、次の文字は数字であり、\d+ がちょうどマッチできるため、ここで .? はマッチを終了し、\d+ が後ろの数字をマッチさせます。したがって、.*? はできるだけ少ない文字をマッチさせ、\d+ の結果は 1234567 となりました。

したがって、マッチを行う際には、文字列の中間ではできるだけ非貪欲マッチを使用し、.*? を代わりに使用して、マッチ結果が欠ける状況を避けるようにしましょう。

ただし、注意が必要です。もしマッチ結果が文字列の末尾にある場合、.*? は何もマッチしない可能性があります。なぜなら、できるだけ少ない文字をマッチさせるからです。例えば:

import re

content = 'http://weibo.com/comment/kEraCN'
result1 = re.match('http.*?comment/(.*?)', content)
result2 = re.match('http.*?comment/(.*)', content)
print('result1', result1.group(1))
print('result2', result2.group(1))

実行結果は以下の通りです:

result1 
result2 kEraCN

.? は何もマッチせず、. はできるだけ多くの内容をマッチさせ、マッチ結果を得ることに成功しました。

修飾子#

正規表現には、マッチのパターンを制御するためのオプションのフラグ修飾子を含めることができます。修飾子はオプションのフラグとして指定されます。例を見てみましょう:

import re

content = '''こんにちは 1234567 世界_これは
正規表現デモです
'''
result = re.match('^ハ.*?(\d+).*?デモ$', content)
print(result.group(1))

上記の例と同様に、文字列に改行文字を追加しましたが、正規表現は同じで、数字をマッチさせるために使用されます。実行結果を見てみましょう:

AttributeError Traceback (most recent call last)
<ipython-input-18-c7d232b39645> in <module>()
      5 '''
      6 result = re.match('^ハ.*?(\d+).*?デモ$', content)
----> 7 print(result.group(1))

AttributeError: 'NoneType' object has no attribute 'group'

実行するとエラーが発生します。つまり、正規表現がこの文字列にマッチせず、結果が None となり、group メソッドを呼び出したために AttributeError が発生しました。

では、なぜ改行文字を加えただけでマッチしなくなったのでしょうか?これは、マッチが改行文字以外の任意の文字を対象としているため、改行文字に出会った時、.*? はマッチできなくなり、マッチが失敗するからです。ここでは re.S 修飾子を追加するだけで、このエラーを修正できます:

result = re.match('^ハ.*?(\d+).*?デモ$', content, re.S)

この修飾子の役割は、. が改行文字を含むすべての文字にマッチするようにすることです。この時、実行結果は以下の通りです:

1234567

この re.S はウェブマッチングでよく使用されます。なぜなら、HTML ノードにはしばしば改行が含まれているため、これを加えることでノード間の改行をマッチさせることができます。

また、必要に応じて使用できる他の修飾子もあります。表 3-3 に示されています。

表 3-3 修飾子

修飾子説明
re.Iマッチを大文字小文字を区別しないようにします
re.Lローカライズされたマッチ(locale-aware)を行います
re.M複数行マッチを行い、^ と $ に影響を与えます
re.S. が改行を含むすべての文字にマッチするようにします
re.UUnicode 文字セットに基づいて文字を解析します。このフラグは \w、\W、\b および \B に影響します
re.Xこのフラグは、正規表現をより理解しやすく書くための柔軟な形式を提供します

ウェブマッチングでは、re.S と re.I がよく使用されます。

エスケープマッチ#

正規表現は多くのマッチパターンを定義しています。例えば、. は改行文字以外の任意の文字にマッチしますが、もしターゲット文字列の中に。が含まれていたら、どうすればよいでしょうか?

ここではエスケープマッチを使用する必要があります。以下はその例です:

import re

content = '(百度) www.baidu.com'
result = re.match('\(百度 \) www\.baidu\.com', content)
print(result)

正規表現マッチパターンの特殊文字に出会った場合、前にバックスラッシュを加えてエスケープすればよいのです。例えば、. は。を使ってマッチさせることができます。実行結果は以下の通りです:

<_sre.SRE_Match object; span=(0, 17), match='(百度) www.baidu.com'>

ここで、元の文字列に成功裏にマッチできたことがわかります。

これらは正規表現を書く際に一般的に使用されるいくつかの知識点であり、それらを熟知することは今後の正規表現マッチを書く上で非常に役立ちます。

前述の通り、match メソッドは文字列の先頭からマッチを開始します。一度先頭がマッチしなければ、全体のマッチが失敗します。以下の例を見てみましょう:

import re

content = '余分な文字列 こんにちは 1234567 世界_これは正規表現デモです 余分な文字列'
result = re.match('こんにちは.*?(\d+).*?デモ', content)
print(result)

ここでの文字列は余分な文字列で始まっていますが、正規表現は「こんにちは」で始まっています。全体の正規表現は文字列の一部ですが、こうしたマッチは失敗します。実行結果は以下の通りです:

None

なぜなら、match メソッドは使用時に先頭の内容を考慮する必要があり、これはマッチ時に便利ではありません。これは、特定の文字列が特定の正規表現のルールに合致するかどうかを検出するのに適しています。

ここで別のメソッド search が登場します。これはマッチ時に文字列全体をスキャンし、最初に成功したマッチの結果を返します。つまり、正規表現は文字列の一部であってもよく、マッチ時に search メソッドは文字列を順にスキャンし、最初にルールに合致する文字列を見つけてマッチ内容を返します。もしスキャンが終了しても見つからなければ、None を返します。

上記のコードの match メソッドを search に変更して、実行結果を見てみましょう:

<_sre.SRE_Match object; span=(13, 53), match='こんにちは 1234567 世界_これは正規表現デモです'>
1234567

この時、マッチ結果を得ることができました。

したがって、マッチを便利にするために、できるだけ search メソッドを使用することができます。

次に、いくつかの例を使って search メソッドの使い方を見てみましょう。

まず、ここにマッチさせる HTML テキストがあります。次に、いくつかの正規表現の例を書いて、対応する情報を抽出します:

html = '''<div id="songs-list">
<h2 class="title"> 经典老歌 </h2>
<p class="introduction">
经典老歌列表
</p>
<ul id="list" class="list-group">
<li data-view="2"> 一路上有你 </li>
<li data-view="7">
<a href="/2.mp3" singer="任贤齐"> 沧海一声笑 </a>
</li>
<li data-view="4" class="active">
<a href="/3.mp3" singer="齐秦"> 往事随风 </a>
</li>
<li data-view="6"><a href="/4.mp3" singer="beyond"> 光辉岁月 </a></li>
<li data-view="5"><a href="/5.mp3" singer="陈慧琳"> 记事本 </a></li>
<li data-view="5">
<a href="/6.mp3" singer="邓丽君"> 但愿人长久 </a>
</li>
</ul>
</div>'''

ul ノードには多くの li ノードが含まれており、その中には a ノードを含むものもあれば、含まないものもあり、a ノードには対応する属性(ハイパーリンクと歌手名)が含まれています。

まず、class が active の li ノード内部のハイパーリンクに含まれる歌手名と歌名を抽出してみましょう。この時、3 番目の li ノードの a ノードの singer 属性とテキストを抽出する必要があります。

この時、正規表現は li で始まり、active というフラグを探し、中間部分は .? でマッチさせます。次に、singer という属性値を抽出する必要があるため、singer="(.?)" を書きます。ここで抽出したい部分は小括弧で囲み、group メソッドを使って取得できるようにします。その両側の境界はダブルクォーテーションです。そして、a ノードのテキストをマッチさせる必要があり、その左側の境界は >、右側の境界は </a> です。ターゲット内容は依然として (.*?) でマッチさせるので、最終的な正規表現は次のようになります:

<li.*?active.*?singer="(.*?)">(.*?)</a>

次に search メソッドを呼び出します。これにより、HTML テキスト全体を検索し、正規表現に合致する最初の内容を返します。

さらに、コードに改行があるため、ここでは 3 番目のパラメータに re.S を渡す必要があります。全体のマッチコードは以下の通りです:

result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>', html, re.S) 
if result:  
    print(result.group(1), result.group(2))

取得したい歌手名と歌名はすでに小括弧で囲まれているため、group メソッドを使って取得できます。

実行結果は以下の通りです:

齐秦 往事随风

これが class が active の li ノード内部のハイパーリンクに含まれる歌手名と歌名です。

もし正規表現から active を外した場合(つまり、class が active でないノードの内容をマッチさせる場合)、どうなるでしょうか?正規表現から active を削除し、コードを以下のように書き換えます:

result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html, re.S)
if result:  
    print(result.group(1), result.group(2))

search メソッドは最初に条件に合致するマッチ対象を返すため、ここでの結果は以下のようになります:

任贤齐 沧海一声笑

active タグを削除した後、文字列の先頭から検索を開始します。この時、条件に合致するノードは 2 番目の li ノードに変わり、後のノードはマッチしなくなります。したがって、実行結果は 2 番目の li ノードの内容になります。

注意すべき点は、上記の 2 回のマッチで、search メソッドの第 3 パラメータに re.S を加えたことです。これにより、.*? が改行をマッチできるようになり、2 番目と 3 番目の li ノードがマッチされました。もしこれを外した場合、結果はどうなるでしょうか?コードは以下の通りです:

result = re.search('<li.*?singer="(.*?)">(.*?)</a>', html)
if result:  
    print(result.group(1), result.group(2))

実行結果は以下の通りです:

beyond 光辉岁月

結果は 4 番目の li ノードの内容に変わりました。これは、2 番目と 3 番目の li ノードが改行文字を含んでいるため、re.S を外すと .*? が改行文字をマッチできなくなり、2 番目と 3 番目の li ノードがマッチされず、4 番目の li ノードは改行文字を含まないため、成功裏にマッチしたからです。

ほとんどの HTML テキストには改行文字が含まれているため、マッチできない問題を避けるために、できるだけ re.S 修飾子を追加する必要があります。

4. findall#

前述の通り、search メソッドは正規表現にマッチする最初の内容を返しますが、もし正規表現にマッチするすべての内容を取得したい場合はどうすればよいでしょうか?この時、findall メソッドを使用します。このメソッドは文字列全体を検索し、正規表現にマッチするすべての内容を返します。

上記の HTML テキストで、すべての a ノードのハイパーリンク、歌手、歌名を取得したい場合は、search メソッドを findall メソッドに置き換えます。結果が返される場合、それはリスト型になるため、各グループの内容を順に取得するためにループを使用する必要があります。コードは以下の通りです:

results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S)
print(results)  
print(type(results))  
for result in results:  
    print(result)  
    print(result[0], result[1], result[2])

実行結果は以下の通りです:

[('/2.mp3', ' 任贤齐 ', ' 沧海一声笑 '), ('/3.mp3', ' 齐秦 ', ' 往事随风 '), ('/4.mp3', 'beyond', ' 光辉岁月 '), ('/5.mp3', ' 陈慧琳 ', ' 记事本 '), ('/6.mp3', ' 邓丽君 ', ' 但愿人长久 ')]
<class 'list'>
('/2.mp3', ' 任贤齐 ', ' 沧海一声笑 ')
/2.mp3 任贤齐 沧海一声笑
('/3.mp3', ' 齐秦 ', ' 往事随风 ')
/3.mp3 齐秦 往事随风
('/4.mp3', 'beyond', ' 光辉岁月 ')
/4.mp3 beyond 光辉岁月
('/5.mp3', ' 陈慧琳 ', ' 记事本 ')
/5.mp3 陈慧琳 记事本
('/6.mp3', ' 邓丽君 ', ' 但愿人长久 ')
/6.mp3 邓丽君 但愿人长久

見ての通り、返されたリストの各要素はタプル型であり、対応するインデックスを使って順に取り出すことができます。

もし最初の内容だけを取得したい場合は、search メソッドを使用します。複数の内容を抽出する必要がある場合は、findall メソッドを使用します。

5. sub#

正規表現を使用して情報を抽出するだけでなく、時にはテキストを変更するためにそれを利用する必要があります。例えば、一連のテキストからすべての数字を削除したい場合、文字列の replace メソッドを使用するだけでは面倒です。この時、sub メソッドを利用できます。以下はその例です:

import re

content = '54aK54yr5oiR54ix5L2g'
content = re.sub('\d+', '', content)
print(content)

実行結果は以下の通りです:

aKyroiRixLg

ここでは最初のパラメータに \d+ を渡してすべての数字にマッチさせ、2 番目のパラメータは置き換える文字列(この場合は空にする)で、3 番目のパラメータは元の文字列です。

上記の HTML テキストで、すべての li ノードの歌名を取得したい場合、正規表現を使って抽出するのは面倒です。例えば、次のように書くことができます:

results = re.findall('<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>', html, re.S)
for result in results:
    print(result[1])

実行結果は以下の通りです:

一路上有你
沧海一声笑
往事随风
光辉岁月
记事本
但愿人长久

この時、sub メソッドを利用すると、a ノードを削除してテキストだけを残し、その後 findall を使って直接抽出することができます:

html = re.sub('<a.*?>|</a>', '', html)
print(html)
results = re.findall('<li.*?>(.*?)</li>', html, re.S)
for result in results:
    print(result.strip())

実行結果は以下の通りです:

<div id="songs-list">
    <h2 class="title"> 经典老歌 </h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2"> 一路上有你 </li>
        <li data-view="7">
            沧海一声笑
        </li>
        <li data-view="4" class="active">
            往事随风
        </li>
        <li data-view="6"> 光辉岁月 </li>
        <li data-view="5"> 记事本 </li>
        <li data-view="5">
            但愿人长久
        </li>
    </ul>
</div>
一路上有你
沧海一声笑
往事随风
光辉岁月
记事本
但愿人长久

見ての通り、a ノードは sub メソッドで処理された後に削除され、その後 findall メソッドを使って直接抽出できました。適切な場合に sub メソッドを利用することで、効果的に作業を進めることができます。

6. compile#

前述のメソッドはすべて文字列を処理するためのものでしたが、最後に compile メソッドについて紹介します。このメソッドは正規表現文字列を正規表現オブジェクトにコンパイルし、後のマッチで再利用できるようにします。以下はその例です:

import re

content1 = '2016-12-15 12:00'
content2 = '2016-12-17 12:55'
content3 = '2016-12-22 13:21'
pattern = re.compile('\d{2}:\d{2}')
result1 = re.sub(pattern, '', content1)
result2 = re.sub(pattern, '', content2)
result3 = re.sub(pattern, '', content3)
print(result1, result2, result3)

例えば、ここに 3 つの日付があり、これらの日付から時間を削除したい場合、sub メソッドを利用できます。このメソッドの最初のパラメータは正規表現ですが、ここで同じ正規表現を 3 回繰り返して書く必要はありません。この時、compile メソッドを使って正規表現を正規表現オブジェクトにコンパイルし、再利用できるようにします。

実行結果は以下の通りです:

2016-12-15  2016-12-17  2016-12-22 

さらに、compile メソッドには修飾子を渡すこともでき、search、findall などのメソッドでは追加で渡す必要がなくなります。したがって、compile メソッドは正規表現に一層の封装を施し、より良い再利用を可能にします。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。