width これでわかった正規表現

これでわかった正規表現
目次
 正規表現とは
 検索
 置換
 正規表現のパターン
 貪欲マッチと非貪欲マッチ
 group()の使い方
 フラグ引数
 正規表現 こんなことできないか


正規表現とは

文字列を検索や置換するときの条件設定です。
言語によって正規表現のコードが違います。はじめて正規表現を使ったのはPHPでした。Pythonでは「あれー!なんか違うみたい。」が感想です。さらに悪いことにwebの検索で最初に出てくるページはまったく説明不要です。いや、嘘が書いてあるページもありました。(こういうのはよくあることです)webの検索でまともなページが最初にヒットしてくれれば、大変ありがたいです。文句言っても仕方ないので自分でまとめることにしました。
呪文のような正規表現をやってみましょう。 /div>

検索
検索に使うreモジュールのメソッド
match
先頭の文字を対象に一致があるかを取得します。

import re

org_text = r"Hello python world. Book is 2400 yen."
new_text = re.match('Hel', org_text)
print(new_text)
org_text = r"Hello python world. Book is 2400 yen." new_text = re.match('python', org_text) print(new_text) 結果:

<re.Match object; span=(0, 3), match='Hel'>
Helが一致しています。部分一致です。

import re

org_text = r"Hello python world. Book is 2400 yen."
new_text = re.match('hel', org_text)
print(new_text)
結果:
	
None
不一致です。大文字・小文字を区別してます。
	
import re

org_text = r"Hello python world. Book is 2400 yen."
new_text = re.match('python', org_text)
print(new_text)
結果:
	
None
2番目の単語以後では一致の対象としていません。何で?最初の単語に重要な意味があって一致しなければそれ以後のデータはどうでもいい。みたいな状況でしょうか。例えば先頭がユーザーIDでAAAで始まる人だけを対象にする。こんなことしか思い浮かばないです。

fullmatch
完全一致を抽出します。

import re

org_text = r"Hello python"
new_text = re.fullmatch('Hello python', org_text)
print(new_text)
結果:

<re.Match object; span=(0, 12), match='Hello python'>
位置文字でも違うとNoneになります。

search
matchが先頭データだけが対象だったのに対しsearchは全部を対象にします。

import re
	
org_text = r"Hello python world. I love python."
new_text = re.search('python', org_text)
print(new_text)
結果:
	
<re.Match object; span=(6, 12), match='python'>
最初に出現したpythonが一致しました。しかし2番目は一致の対象になりませんでした。複数の一致する文字があっても最初に出現した文字だけが抽出されます。

 findall
一致する文字があれば全部取得します。

import re
	
org_text = r"Hello pySerial. I love pyGame."
new_text = re.findall('py', org_text)
print(new_text)
結果:

['py', 'py']
パターンをpyにしたのでpyだけの結果です。また、文字の出現位置がありません。出現位置を取得するにはfiinditerを使います。

finditer
finditerは、パターンに一致するものを全てイテレータというもので返します。その要素はmatchオブジェクトになります。

import re

org_text = r"Hello pySerial. I love pyGame."
result = re.finditer('py', org_text)
for match in result:
    print(match)
結果:

<re.Match object; span=(6, 8), match='py'>
<re.Match object; span=(23, 25), match='py'>
抽出した文字列の出現位置を取得できました。

置換
検索はたくさんのメソッドがありましたが、置換は subだけです。

org_text = r"Hello pySerial. I love pyGame."
res = re.sub('py', 'my', org_text)
print(res)
結果:

Hello mySerial. I love myGame.
pySerialがmySeriralにpyGameがmyGameに置換されています。置換は文字列の検証にも使います。たとえば英数字と英文字からなるパスワードを例にします。

org_text = r"sdi9876"
res = re.sub('[0-9a-z\a-Z]','', text)
print(res)
結果は何も表示されません。つまり全部の文字がなくりました。

org_text = r"sdi-9876"
res = re.sub('[0-9a-zA-Z]','', text)
print(res)
英数字、英文字ではない-が残りました。このように正しい文字を消去して不正な文字を残すことによる検証方法です。

元の文字列を整形して見やすくこともできます。
例:09012345678 →090-1234-5678

org_text = r'09012345678'
res = re.sub(r'([0-9]{3})([0-9]{4})([0-9]{4})', r'\1-\2-\3', org_text)
最初の数字3桁090-次の4桁-1234-次の4桁4567
      \1                     \2                    \3          
\1=最初の数字3桁 \2=次の4桁 \3=次の4桁 となります。