Menu
日本語

Python 正規表現入門 | reモジュールの使い方を解説

Pythonのreモジュールを使った正規表現の基本を実例で解説。search・match・findall・subからグループ化、置換までひと通り押さえます。

正規表現を使うべき場面

Python の正規表現は、テキストのパターンを記述するための小さな専用言語のようなものです。強力ですが、つい使いすぎてしまいがちな機能でもあります。

re モジュールに手を伸ばす前に、まずは普通の文字列メソッドで十分じゃないか考えてみましょう。.split().replace().startswith()"target" in text といったものは、同じことを正規表現でやるよりも速く、読みやすく、バグも入りにくいです。正規表現の出番は、探したいパターンが ある程度の構造を持ちつつも 固定の文字列操作では対応しきれないくらい柔軟なとき。たとえばメールアドレス、電話番号、形式の決まったログ行、HTML や Markdown の断片など、「この手のやつを見つけたい」という検索です。

基本の記法

正規表現の パターン は、「何を探しているか」を表す文字列です。よく使うパーツを並べてみます。

  • . — 任意の 1 文字
  • \d — 数字 1 文字(0〜9)
  • \w — 「単語」を構成する文字(英字・数字・アンダースコア)
  • \s — 空白文字
  • ^ — 文字列の先頭
  • $ — 文字列の末尾
  • [abc] — a、b、c のいずれか 1 文字
  • [^abc] — a、b、c 以外の任意の 1 文字
  • a|b — a または b
  • * — 直前の要素の 0 回以上の繰り返し
  • + — 1 回以上の繰り返し
  • ? — 0 回または 1 回
  • {3} — ちょうど 3 回
  • {2,5} — 2 回以上 5 回以下
  • ( ... ) — グループ化(中身をキャプチャする)

実務で使う正規表現のほとんどは、これだけで書けてしまいます。

主な関数

re.search の使い方

re.search(pattern, text) は、文字列のどこかに最初に現れるマッチを探します。マッチオブジェクトか、見つからなければ None を返します。

main.py
Output
Click Run to see the output here.

正規表現のパターンには必ず raw 文字列(r"...")を使いましょう。そうしないと、Python がバックスラッシュを文字列エスケープとして解釈してしまい、書いたつもりのパターンとは別物になってしまいます。

re.match(pattern, text)search と似ていますが、文字列の先頭でのみマッチを試みます。

main.py
Output
Click Run to see the output here.

ほとんどの場合は search を使えば事足ります。

re.findall(pattern, text) は、重ならないマッチをすべてリストで返してくれます。

main.py
Output
Click Run to see the output here.

findall が返すのは文字列であって、マッチオブジェクトではない点に注意してください。パターンにグループが1つだけ含まれる場合はそのグループの中身が返り、複数のグループがある場合はタプルのリストになります。

グループ化によるキャプチャ

パターン内の丸括弧 () は、その中にマッチした部分をキャプチャします。

main.py
Output
Click Run to see the output here.

名前付きグループ を使うと、コードがぐっと読みやすくなります。

main.py
Output
Click Run to see the output here.

グループが2つ以上になると、名前を付けておいた方が抽出するコードがぐっと読みやすくなります。

re.sub で置換する

re.sub(pattern, replacement, text) は、マッチした部分をすべて置き換えます。

main.py
Output
Click Run to see the output here.

これで数字以外をすべて取り除けます。置換側ではキャプチャしたグループを \1\2 のように参照できます。raw 文字列を使う場合は \g<1> と書いた方が分かりやすいでしょう。

main.py
Output
Click Run to see the output here.

置換部分には関数を渡すこともできます。単純な置き換えでは表現できない変換をしたいときに便利です。

main.py
Output
Click Run to see the output here.

パターンをコンパイルして使い回す

同じパターンを何度も使う場合、特にループの中で繰り返し使うようなときは、一度コンパイルしておくのがおすすめです。

main.py
Output
Click Run to see the output here.

コンパイル済みのパターンでも、searchmatchfindallsub といった同じメソッドが使えます。ただし第一引数にパターンを渡す必要はありません。少しだけ高速で、コードも読みやすくなることが多いです。

フラグ

よく使う修飾子は、flags= 引数で渡すか、| で組み合わせて指定します。

  • re.IGNORECASE (re.I) — 大文字・小文字を区別せずにマッチします。
  • re.MULTILINE (re.M) — ^$ が文字列全体の先頭・末尾だけでなく、各行の先頭・末尾にもマッチするようになります。
  • re.DOTALL (re.S) — . が改行にもマッチするようになります(デフォルトではマッチしません)。
  • re.VERBOSE (re.X) — パターン内に空白や # によるコメントを書けるようになり、可読性が向上します。
main.py
Output
Click Run to see the output here.

re.VERBOSE は複雑なパターンを書くときに特に便利です。

main.py
Output
Click Run to see the output here.

複数行でコメントを添えた正規表現は、意味不明な一行パターンに比べてメンテナンスが圧倒的にラクになります。

貪欲マッチと最小マッチ

量指定子(*+?{n,})は、デフォルトでは 貪欲(greedy) に動作し、マッチできる範囲を可能な限り長く取ろうとします。末尾に ? を付けると 最小マッチ(lazy) に切り替わります。

main.py
Output
Click Run to see the output here.

貪欲マッチの方は <b> から </i> までまるごと拾ってしまっていて、たぶん欲しかった結果とは違いますよね。最小マッチの .+? なら最初の > の時点で止まってくれます。

(余談ですが、本番で HTML を正規表現でパースするのはやめましょう。html.parser か BeautifulSoup を使ってください。上の例はあくまで貪欲マッチの挙動を示すためのものです。)

実践的なサンプル

シンプルなログ形式の行をパースしてみます。

main.py
Output
Click Run to see the output here.

たった数行でこれだけのことができてしまいます。

ちょっとしたコツ

  • パターンは必ず raw 文字列(r"...")で書く。
  • まずは動く最小のパターンから始め、あとから絞り込む。
  • グループが2つ以上になったら名前付きグループを使う。
  • 繰り返し使うパターンは compile しておく。
  • 正規表現は普通の文字列メソッドより遅い。.split() で足りるなら .split() を使う。

次は: エラーとデバッグ

これで実データを扱うひと通りのツアー(ファイル、JSON、CSV、HTTP、日付、そして正規表現)は終わりです。とはいえ、実際のプログラムを書けば遅かれ早かれエラーに遭遇します。そして Python のトレースバックをきちんと読めるようになることは、デバッグ力を伸ばすうえで何よりも効きます。最終章では例外処理と、現場でよく出会う代表的なエラーについて見ていきます。

よくある質問

Pythonにおける正規表現とは?

正規表現(regex)は、文字列のパターンを記述するための小さな言語です。Pythonでは標準ライブラリの re モジュールを使って、パターン検索・抽出・置換ができます。ただし、単純な文字列操作なら .split().replace() などの文字列メソッドで十分。正規表現はあくまで、構造のあるパターンをマッチさせたいときの切り札として使うのがおすすめです。

re.match と re.search の違いは?

re.match は文字列の先頭からしかマッチを試みません。一方 re.search は文字列全体を走査して、どこかにマッチがあれば最初の一件を返します。迷ったときは search を使うのが無難です。多くの人が直感的に期待する挙動はこちらのほうです。

正規表現のパターンは raw 文字列(r"...")で書くべき?

はい、基本的に raw 文字列で書くのがおすすめです。正規表現には \d\s\b のようにバックスラッシュを含む記号が頻出しますが、通常の文字列だとPythonがエスケープシーケンスとして解釈してしまいます。r'\d+' のように r を付けておけば文字列がそのまま扱われるので、パターンが読みやすくなりバグも減ります。

Coddyでコードを学ぼう

始める