検索や置換の強力なオトモといえば、正規表現。
今回はPythonで、正規表現を使った検索についてです!
import
Pythonで正規表現を使うには、コチラをimportします。
import re
正規表現でマッチ箇所を検索
関数 | 効果 |
---|---|
match(pattern, str) | 先頭から比較してマッチするか? |
search(pattern, str) | 先頭から検索して行ってマッチするものがあるか? |
例えば、この文字列が検索対象とします。
>>> target = 'xxxx0000yyyy1111'
コレに対してmatch/searchを試してみましょう。
>>> re.match(r'[a-z]{4}', target) <_sre.SRE_Match object; span=(0, 4), match='xxxx'> >>> re.search(r'[a-z]{4}', target) <_sre.SRE_Match object; span=(0, 4), match='xxxx'> >>> >>> re.match(r'[0-9]{4}', target) >>> re.search(r'[0-9]{4}', target) <_sre.SRE_Match object; span=(4, 8), match='0000'>
'[a-z]{4}'の場合、どちらもマッチしたので、結果が返ってきています。
どちらも「最初にヒットしたパターン」が結果として返ってきます。
'[0-9]{4}'の場合、matchは「先頭から比較してマッチするか?」をチェックするので、「マッチしていない」状態となってます。
マッチしていない場合、Noneが返ってきます。
だからmatchでは結果が何も表示されていませんね。
正規表現で全てのマッチ箇所を取得
「マッチした全てのパターンを取得したい!」
という場合は、「findall」を使用します。
こんな感じ。
>>> target = 'xxxx0000yyyy1111' >>> re.findall('[a-z]{4}', target) ['xxxx', 'yyyy']
リストで返ってくるので、取り扱いもラクラクですね!
>>> res = re.findall('[a-z]{4}', target) >>> for s in res: ... print(s) ... xxxx yyyy
()を使うとうまくヒットしないケース
findallを試していて、うまくヒットしないケースに遭遇しました。
例えばこんな文字列を検索するとします。
>>> target = 'x0x0x0x0,x0x0x0x0,x0x0x0x0,x0x0x0x0'
このとき、「','以外のものをマッチするようにして、リストとして取得したい」とします。
こういうのが欲しいわけです。
['x0x0x0x0', 'x0x0x0x0', 'x0x0x0x0', 'x0x0x0x0']
ということでfindallを使っていきます。
例えばこのようにすると、望みどおりのものを取得することができました。
>>> re.findall(r'[a-z][0-9][a-z][0-9][a-z][0-9][a-z][0-9]', target) ['x0x0x0x0', 'x0x0x0x0', 'x0x0x0x0', 'x0x0x0x0']
しかしちょっとクドいですよね。
ということで、「繰り返し」を使ってを短縮しよう!
と思ったその時……
>>> re.findall(r'([a-z][0-9]){4}', target) ['x0', 'x0', 'x0', 'x0']
なぜかマッチはしてる扱いだが、繰り返し部分が取られていない……
正規表現をチェックするサイトで見ても、特に問題がなさそう……
Regex Test Drive | 正規表現オンラインテストサイト
バグ……?
参考
コチラを参考にしました。ありがとうございました!
正規表現 HOWTO — Python 3.6.5 ドキュメント
あとがき
ということで、Pythonによる正規表現での検索についてでした!
matchで「先頭一致」を使う以外は、基本的にfindallでいいんじゃないかなーと思っています。
ただ、今回のように「なぜかうまく取得できないケース」などがある可能性があるので、適宜注意が必要かもしれません。