FC2ブログ

子供の落書き帳 Remix

15/4/13:ひと月に一度更新するブログになってしまっている

スポンサーサイト
--/--/--(--) --:--:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

pythonの正規表現のmatch, search, findall関数の違いを調べて整理した
2018/07/01(日) 22:18:41

以下のサイトが役に立った。自分で調査した結果も併せて整理しておく。
Pythonでの正規表現の使い方 - Qiita
正規表現 HOWTO ? Python 3.6.5 ドキュメント

共通


pythonのバージョンは3.6.0。

正規表現でマッチするものが見つかったときには、matchオブジェクトというオブジェクトが使われる。
matchオブジェクトの中に、マッチした箇所の情報が格納される。
(今回はmatchオブジェクトの中身の構造については触れない)

match関数 文字列の先頭だけを探す


これは検索対象の先頭からだけ検索して、マッチするものがあるか判定する。
探しているパターンが先頭にあればマッチするが、途中に含まれていてもマッチしない。

・マッチしなかったらNoneが返る。
・マッチした場合はmatchオブジェクトが返る。
・matchオブジェクトの中にはマッチした箇所の情報が入っている。

以下は特殊なシンタックスを使わない、ごく単純な例だ。
下の例の2つ目では、では"regular expression"の中に"lar"は含まれているが、最初ではないのでマッチせず、Noneが返っている。


import re

result = re.match("reg", "regular expression")
print(result)
print(type(result))
# 出力:
# <_sre.SRE_Match object; span=(0, 3), match='reg'>
#

result = re.match("lar", "regular expression")
print(result)
print(type(result))
# 出力:
# None
#



search関数 文字列の全ての位置を探す。


これは検索対象の位置にかかわらず検索する。


result = re.search("reg", "regular expression")
print(result)
print(type(result))
# 出力:
# <_sre.SRE_Match object; span=(0, 3), match='reg'>
#

result = re.search("lar", "regular expression")
print(result)
print(type(result))
# 出力:
# <_sre.SRE_Match object; span=(4, 7), match='lar'>
#


文字列の途中でもマッチしているのが、match関数と違う点である。
また、マッチしない場合は、match関数と同様にNoneが返る。

search関数の注意:パターンにマッチするのが2つ以上ある場合は最初の1つだけが返る。

"regular expression"の中で、「アルファベットが1文字以上連続する箇所」を探してみよう。
これは「\w+」と書き表せる。
(厳密には、\wはアルファベット、数字、およびアンダースコアの集合である)
このパターンに該当するのは「regular」と「expression」の2つだが、返り値を見ると最初の「regular」の部分だけが入っている。


result = re.search("\w+", "regular expression")
print(result)
print(type(result))
# 出力:
# <_sre.SRE_Match object; span=(0, 7), match='regular'>
#



findall関数 パターンに当てはまるもの全てをリストにして返す



マッチする箇所が複数あったら、1つ目だけではなく全て返してほしい、という場合もあるだろう。
このような場合ではfindall関数を使う。

返り値の決まり方は結構ややこしい。
Python 3.6.5 ドキュメントのre.findallの箇所にはこう書かれている。
「Return all non-overlapping matches of pattern in string, as a list of strings. (中略) If one or more groups are present in the pattern, return a list of groups; this will be a list of tuples if the pattern has more than one group. 」
3つの場合分けがある。順に見ていこう。

まず、1つ目の場合。パターンの指定時にグルーピングの( )を使わない場合、返り値は文字列のリストである。

result = re.findall("\w+", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# 出力:
# ['regular', 'expression']
#
#



グルーピングの( )を使う場合、まずパターン内に( )が1つだけであれば、グループ(内にある文字列)のリストになる。
下の例の2つ目では、マッチングは1つ目の例と同様になるが、( )の中にeが入っていないので返り値にeが含まれていない。

result = re.findall("(e.)", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# 出力:
# ['eg', 'ex', 'es']
#
#

result = re.findall("e(.)", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# 出力:
# ['g', 'x', 's']
#
#


そしてパターン内に( )が2つ以上ある場合、グループ(内にある文字列)をタプルにしたもののリストになる。
下の例の2つ目では( )がネスト(入れ子)になっているが、タプル内の順序は左括弧の登場順である。

result = re.findall("(e)(.)", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# [('e', 'g'), ('e', 'x'), ('e', 's')]
#
#

result = re.findall("(e)((.)..)", "regular expression")
print(result)
print(type(result))
print(type(result[0]))
# 出力:
# [('e', 'gul', 'g'), ('e', 'xpr', 'x'), ('e', 'ssi', 's')]
#
#



最後に、返り値の方式にかかわらず、マッチしない場合は空のリストが返る。

result = re.findall("AAAAA", "regular expression")
print(result)
print(type(result))
# 出力:
# []
#



まとめ


3つの関数の仕様を整理しておこう。
■match関数は文字列の先頭だけを探す。
■search関数は文字列の全ての位置を探す。パターンに当てはまるものが複数ある場合は最初のものを返す。
■findall関数は文字列の全ての位置を探す。パターンに当てはまるもの全てをリストにして返す。返り値は以下の3通りある:
  -パターンの指定にグルーピングの( )を使わない場合、返り値は文字列のリストである。
  -パターンの指定にグルーピングの( )を使う場合、パターン内に( )が1つだけであれば、グループ(内にある文字列)のリストになる。
  -パターンの指定にグルーピングの( )を使う場合、パターン内に( )が2つ以上であれば、グループ(内にある文字列)をタプルにしたもののリストになる。


書いたきっかけとおまけ



正規表現でsearchを使うべきところでmatchを使っていて、ずっとNoneが返ってきてしまい、だいぶ時間を費やした。

何も考えずに「python 正規表現」でググったとき、python公式ドキュメントで最初に見つかるのはこれだ。
6.2. re ? 正規表現操作 ? Python 3.6.5 ドキュメント
これはリファレンスであり、初めて使う人が参考にするには厳しい。
終わり近くの6.2.5.3. search() vs. match()という箇所で一応言及はしているのだが、最初に見た人がここにたどり着くのは難しい。
同じ公式ドキュメントなら、以下のほうがオススメである。
正規表現 HOWTO ? Python 3.6.5 ドキュメント
  1. 2018/07/01(日) 22:18:41|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:0

コメント


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://luvtome.blog5.fc2.com/tb.php/646-41c27e0b
この記事にトラックバックする(FC2ブログユーザー)

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。