正規表現のフラグは、マッチの挙動を変えるオプションです。たとえば「大文字小文字を区別しない」「^と$を行ごとに効かせる」「.を改行にもマッチさせる」といった切り替えができます。
たとえば「Cat CAT cat」からcatを取り出す場合、ふつうは大文字小文字が区別され、小文字のcatしか取れません。ここに「大文字小文字を無視する」フラグre.IGNORECASEを渡すと、Cat・CAT・catのすべてが取れます。フラグは、re.findallなどの関数に引数として渡して使います。
本記事では、よく使う5つのフラグと、パターンの中に直接書くインラインフラグを、Pythonのreモジュールで一つずつ整理します。reモジュールは標準モジュールなのでインストールは不要です。
なお、本記事で使う^・$・.・\d・\w・\sなどの基本構文や(?:...)など?で始まる丸かっこの記法(グループ)は過去に記事で扱っています。
目次
- フラグの一覧
- 大文字小文字を無視する(re.IGNORECASE)
- 行ごとに先頭・末尾を判定する(re.MULTILINE)
- ドットを改行にもマッチさせる(re.DOTALL)
- パターンに空白やコメントを書く(re.VERBOSE)
- ASCIIだけにマッチさせる(re.ASCII)
- 複数のフラグを同時に使う
- パターンに直接書く(インラインフラグ)
- まとめ
フラグの一覧
主要なフラグを、先に一覧で示します。短縮形(re.Iなど)は正式名と同じ意味で、どちらを使っても同じように動作します。
| フラグ | 短縮形 | はたらき |
|---|---|---|
re.IGNORECASE | re.I | 大文字小文字を区別せずにマッチする |
re.MULTILINE | re.M | ^と$を各行の先頭・末尾にもマッチさせる |
re.DOTALL | re.S | .を改行文字にもマッチさせる |
re.VERBOSE | re.X | パターン中の空白とコメントを無視し、読みやすく書ける |
re.ASCII | re.A | \d・\w・\sなどをASCII文字だけに限定する |
フラグは関数のflags引数に渡します(re.findall(パターン, 文字列, re.I))。複数を同時に使うときは|でつなぎます。また、パターンの中に直接書くインライン形((?i)や(?i:...))もあります。
大文字小文字を無視する(re.IGNORECASE)
re.IGNORECASE(短縮形re.I)を渡すと、大文字小文字を区別せずにマッチします。
print(re.findall(r"cat", "Cat CAT cat")) # ['cat']
print(re.findall(r"cat", "Cat CAT cat", re.IGNORECASE)) # ['Cat', 'CAT', 'cat']フラグなしでは小文字のcatしか一致しませんが、re.IGNORECASEを付けるとCat・CAT・catのすべてが一致します。
re.IGNORECASEはASCIIだけでなく、Unicodeの大文字小文字も対象です(Äとäなど)。
print(re.findall(r"ä", "Ä ä", re.IGNORECASE)) # ['Ä', 'ä']ASCIIの範囲(a〜z、A〜Z)だけにしたい場合は、後述のre.ASCIIを併用します。
print(re.findall(r"ä", "Ä ä", re.IGNORECASE | re.ASCII)) # ['ä']行ごとに先頭・末尾を判定する(re.MULTILINE)
^(先頭)と$(末尾)は、ふつうは文字列全体の先頭・末尾だけにマッチします。re.MULTILINE(短縮形re.M)を渡すと、改行で区切られた各行の先頭・末尾にもマッチするようになります。
text = "apple pie\nbanana bread\ncherry cake"
print(re.findall(r"^\w+", text)) # ['apple']
print(re.findall(r"^\w+", text, re.MULTILINE)) # ['apple', 'banana', 'cherry']^\w+は「行頭の単語」を表します。フラグなしでは、^が文字列全体の先頭にしかマッチしないため、1行目のappleだけが取れます。re.MULTILINEを付けると、^が各行の先頭にマッチし、各行の先頭の単語apple・banana・cherryが取れます。
末尾の$も同じです。同じtextに対して、行末の単語を表す\w+$で見てみます。
print(re.findall(r"\w+$", text)) # ['cake']
print(re.findall(r"\w+$", text, re.MULTILINE)) # ['pie', 'bread', 'cake']フラグなしでは、$が文字列全体の末尾にしかマッチしないため、最終行のcakeだけが取れます。re.MULTILINEを付けると、$が各行の末尾にマッチし、各行の末尾の単語pie・bread・cakeが取れます。
ドットを改行にもマッチさせる(re.DOTALL)
.は、ふつうは改行文字(\n)以外の任意の1文字にマッチします。re.DOTALL(短縮形re.S)を渡すと、.が改行にもマッチするようになります。
text = "start\nend"
print(re.findall(r"start.end", text)) # []
print(re.findall(r"start.end", text, re.DOTALL)) # ['start\nend']フラグなしでは.が改行にマッチしないため、結果は空です。re.DOTALLを付けると改行にもマッチし、start\nend全体が取れます。改行をまたいでまとめてマッチさせたいときに使います。
パターンに空白やコメントを書く(re.VERBOSE)
re.VERBOSE(短縮形re.X)を渡すと、パターン中の空白と、#から行末までのコメントが無視されます。複雑なパターンを、改行・字下げ・コメント付きで読みやすく書けます。
pattern = r"""
\d{3} # 市外局番
- # ハイフン
\d{4} # 番号
"""
print(re.findall(pattern, "012-3456 と 78-9012", re.VERBOSE)) # ['012-3456']このパターンは、空白とコメントを取り除くと\d{3}-\d{4}と同じです。012-3456はこの形に合うので取れ、78-9012は先頭が2桁なので取れません。
注意点として、re.VERBOSEでは空白そのものが無視されます。空白を文字としてマッチさせたいときは、\ (バックスラッシュ+空白)や[ ](空白だけの文字クラス)と書きます。
ASCIIだけにマッチさせる(re.ASCII)
\d・\w・\sは、Python3では既定でUnicode全体(日本語や全角文字なども含む)にマッチします。re.ASCII(短縮形re.A)を渡すと、これらをASCII文字だけに限定できます。
print(re.findall(r"\w+", "今はPython3")) # ['今はPython3']
print(re.findall(r"\w+", "今はPython3", re.ASCII)) # ['Python3']フラグなしでは、\wが今はも語の文字とみなすため、今はPython3全体が1つのまとまりとして取れます。re.ASCIIを付けると、\wは英数字とアンダースコア(_)だけになり、今はは除外されてPython3だけが取れます。半角の英数字だけを対象にしたいときに使います。
複数のフラグを同時に使う
複数のフラグを同時に使うときは、|(縦棒)でつなぎます。
print(re.findall(r"^apple", "Apple\nAPPLE", re.IGNORECASE | re.MULTILINE)) # ['Apple', 'APPLE']re.IGNORECASE | re.MULTILINEで、「大文字小文字を区別せず」かつ「各行の先頭で」マッチします。Apple(1行目)とAPPLE(2行目)の両方が取れます。3つ以上でもre.I | re.M | re.Sのようにつなげます。
パターンに直接書く(インラインフラグ)
フラグは、flags引数で渡すほかに、パターンの中に直接書くこともできます。これをインラインフラグと呼びます。書き方は次の3つです。
| 書き方 | 効果 |
|---|---|
(?i) | パターン全体に効かせる(先頭に置く) |
(?i:…) | ...の部分だけに効かせる |
(?-i:…) | ...の部分だけフラグを外す |
表のiは、re.IGNORECASEの短縮形re.Iを小文字にしたものです。同じくmはre.M(MULTILINE)、sはre.S(DOTALL)、xはre.X(VERBOSE)、aはre.A(ASCII)に対応し、iの位置をこれらに置き換えれば同じように使えます。
パターン全体に効かせるには、先頭に(?i)のように書きます。
print(re.findall(r"(?i)cat", "Cat CAT cat")) # ['Cat', 'CAT', 'cat'](?i)はre.IGNORECASEを渡すのと同じです。なお、パターン全体に効かせる(?i)は、パターンの先頭に置く必要があります。
パターンの一部にだけ効かせたいときは、(?i:...)という形で、対象を丸かっこで囲みます。
print(re.findall(r"(?i:cat)dog", "CATdog catDOG Catdog")) # ['CATdog', 'Catdog'](?i:cat)の部分だけが大文字小文字を無視するので、catはCATやCatでも一致しますが、続くdogは区別されます。catDOGのDOGはdogと一致しないため、取れるのはCATdogとCatdogです。
逆に、(?-i:...)と書くと、その部分だけフラグを外せます。
print(re.findall(r"(?i)(?-i:CAT)dog", "CATdog catdog CATDOG")) # ['CATdog', 'CATDOG']ここでは(?i)で全体を大文字小文字無視にしつつ、(?-i:CAT)の部分だけ区別を戻しています。CATは大文字でなければならず、dogは区別されないので、CATdogとCATDOGが取れます(catdogはCATの部分が小文字なので取れません)。
まとめ
正規表現のフラグについて、reモジュールで例を示しながら確認しました。
re.IGNORECASE(re.I)は大文字小文字を区別せずにマッチする。re.MULTILINE(re.M)は^と$を各行の先頭・末尾にもマッチさせる。re.matchは付けても先頭のみ。re.DOTALL(re.S)は.を改行にもマッチさせる。re.VERBOSE(re.X)はパターン中の空白とコメントを無視し、読みやすく書ける。re.ASCII(re.A)は\d・\w・\sなどをASCII文字だけに限定する。
複数のフラグは|でつなぎ、パターンに直接書くインライン形(全体は(?i)、一部は(?i:...)/(?-i:...))も使えます。
なお、次の記事「正規表現のreモジュールの関数(Python)」で正規表現を応用した検索・置換などの関数を取り扱います。