Pythonの re モジュールで、改行を含むテキストデータを扱う際に必須となるのが「フラグ」の指定です。特に、行単位でのマッチングを行いたい場合の re.MULTILINE と、改行をまたいでマッチングを行いたい場合の re.DOTALL は、挙動を正しく理解していないと意図した結果が得られません。
この記事では、チャットログや複雑なテキストデータを例に、これらのフラグが特殊文字(^, $, .)に与える影響と、その使い分けを解説します。
特殊文字とフラグの対応表
| 特殊文字 | デフォルトの挙動 | re.MULTILINE (複数行) | re.DOTALL (改行一致) |
. (ドット) | 改行以外の1文字にマッチ | 変化なし | 改行を含む全ての文字にマッチ |
^ (キャレット) | 文字列全体の先頭のみ | 各行の行頭 | 変化なし |
$ (ドル) | 文字列全体の末尾のみ | 各行の行末 | 変化なし |
実装例:チャットログの解析
ユーザーからのメッセージが複数行にわたる場合があるチャットログを想定し、特定のパターンを抽出します。
シナリオ
以下のような形式のログから、2つの異なる抽出を行います。
- 各メッセージのヘッダー行(ユーザー名と日時)だけを取得したい。
- ヘッダーからメッセージ本文を含めた1つの発言ブロック全体を取得したい。
ソースコード
import re
# 解析対象:チャットアプリのログデータ
# ユーザー名とタイムスタンプの行があり、その後にメッセージが続く(複数行の場合あり)
chat_log = """[UserA] 10:00
Hello everyone.
Check this out.
[UserB] 10:05
Good morning!
I will check it later.
[UserC] 10:10
Thanks."""
# パターンA: 行頭の [User...] を含む行だけを抽出
# ^ : 行頭、.+ : 1文字以上
pattern_line = r"^\[User.*\].+$"
# パターンB: [User...] から次の空行(または末尾)までのブロック全体を抽出
# ^ : 行頭、.+? : 最短マッチ、$ : 行末(ブロックの終わり)
pattern_block = r"^\[User.*?\].+?$"
print("--- 1. re.MULTILINE のみ使用 ---")
# ^ と $ を「各行」の先頭・末尾にマッチさせる
# 結果: ヘッダー行だけが抽出される(メッセージ本文は無視される)
headers = re.findall(pattern_line, chat_log, flags=re.MULTILINE)
for h in headers:
print(f"Header found: {h}")
print("\n--- 2. re.MULTILINE | re.DOTALL の併用 ---")
# MULTILINE : ^ を各ブロックの開始位置にマッチさせる
# DOTALL : . を改行にもマッチさせ、複数行のメッセージを含める
# 結果: 各ユーザーの発言ブロック全体が抽出される
blocks = re.findall(pattern_block, chat_log, flags=re.MULTILINE | re.DOTALL)
for i, block in enumerate(blocks, 1):
print(f"--- Block {i} ---\n{block}")
実行結果
--- 1. re.MULTILINE のみ使用 ---
Header found: [UserA] 10:00
Header found: [UserB] 10:05
Header found: [UserC] 10:10
--- 2. re.MULTILINE | re.DOTALL の併用 ---
--- Block 1 ---
[UserA] 10:00
Hello everyone.
Check this out.
--- Block 2 ---
[UserB] 10:05
Good morning!
I will check it later.
--- Block 3 ---
[UserC] 10:10
Thanks.
解説
1. 各行を個別に処理する (re.MULTILINE)
デフォルトでは ^ は文字列全体の先頭([UserA]の前)にしかマッチしません。re.MULTILINE を指定することで、^ が「各行の始まり」を意味するようになり、途中の [UserB] や [UserC] の行頭も検出できるようになります。ログの見出し行だけをリスト化したい場合に有効です。
2. 改行を含む範囲をまとめる (re.DOTALL)
メッセージ本文に改行が含まれている場合、通常の . は改行で止まってしまいます。re.DOTALL を指定することで、. が改行文字(\n)も飲み込むようになり、複数行にわたるテキストブロックを一括でキャプチャできます。
この2つのフラグは、flags=re.MULTILINE | re.DOTALL のようにビット演算子 | を使って同時に指定することが可能です。これにより、「行頭から始まり、複数行にわたる内容を含んでマッチする」という柔軟な検索が実現できます。
