【Python初心者】正規表現の書き方とマッチオブジェクトの使い方まとめ

Pythonで複雑な文字列検索や抽出を行いたいときに便利なのが「正規表現（regular expression）」です。  
`re` モジュールを使えば、特定のパターンを持つ文字列を抽出したり、検出したりすることができます。

この記事では、基本的な正規表現の書き方と、それによって得られる **マッチオブジェクト（Match object）** の使い方、さらに `re.search()` と `re.compile()` の違いについて、自分の学習の記録としてまとめてみました。

## 正規表現を使うには

まずは `re` モジュールをインポートします。

```python
import re
```

## raw文字列リテラル（`r"..."`）とは？

正規表現では、`\d` や `\s` などの **バックスラッシュ（`\`）を含む記号**が頻出します。  
Pythonでは `\` を特殊な意味として解釈してしまうため、**正しくパターンを書くためには raw（生）文字列**にする必要があります。

```python
print("\n")   # 改行になる
print(r"\n")  # \ と n をそのまま表示 → \n
```

このように、正規表現では常に `r"..."` の形式で書くのが基本です。

## `{}` の意味（繰り返し指定）

中かっこ `{}` は「**直前の文字やパターンの繰り返し回数**」を表します。

| パターン | 説明 |
|----------|------|
| `{n}`    | ちょうど n 回繰り返す |
| `{n,}`   | n 回以上繰り返す     |
| `{n,m}`  | n 回以上 m 回以下繰り返す |

例：

```python
r"\d{3}"    # 数字が3桁連続
r"a{2,4}"   # aが2〜4回連続
```

## よく使う正規表現パターン一覧

| パターン | 説明 | マッチ例 |
|----------|------|----------|
| `.`      | 任意の1文字           | `"a"`, `"1"` |
| `\d`     | 数字（0〜9）          | `"1"`, `"9"` |
| `\w`     | 単語文字（英数字＋_） | `"a"`, `"0"`, `"_"` |
| `\s`     | 空白文字（スペース・改行など） | `" "`, `"\t"` |
| `^`      | 行の先頭               | `^abc` → "abc"で始まる |
| `$`      | 行の末尾               | `abc$` → "abc"で終わる |
| `*`      | 直前の文字が0回以上     | `a*` → `""`, `"a"`, `"aaa"` |
| `+`      | 直前の文字が1回以上     | `a+` → `"a"`, `"aa"` |
| `?`      | 直前の文字が0回または1回 | `a?` → `""`, `"a"` |
| `[]`     | 指定文字のいずれか      | `[aeiou]` → 母音にマッチ |
| `|`      | OR（または）            | `cat\|dog` → "cat"または"dog" |

## 基本的な使い方：re.search()

`re.search()` は、文字列の中にパターンが存在するかを調べ、**最初に見つかったマッチ1つを返します**。

```python
import re

text = "My number is 123-4567."
match = re.search(r"\d{3}-\d{4}", text)

if match:
    print("Matched:", match.group())  # Matched: 123-4567
```

## マッチオブジェクトの使い方

`re.search()` がマッチした場合、**マッチオブジェクト**が返されます。  
このオブジェクトには、マッチした文字列やその位置情報が格納されています。

| メソッド | 説明 |
|----------|------|
| `.group()` | マッチした文字列全体 |
| `.start()` | マッチの開始位置（インデックス） |
| `.end()`   | マッチの終了位置（インデックス） |
| `.span()`  | 開始〜終了の範囲をタプルで返す |

```python
text = "My number is 123-4567."
match = re.search(r"\d{3}-\d{4}", text)

if match:
    print("group():", match.group())   # 123-4567
    print("start():", match.start())   # 13
    print("end():", match.end())       # 21
    print("span():", match.span())     # (13, 21)
```

## パターンを事前に準備する：re.compile()

同じパターンを何度も使う場合は、`re.compile()` で事前にコンパイルしておくと効率的です。

```python
pattern = re.compile(r"\d{3}-\d{4}")

text = "Call me at 987-6543."
match = pattern.search(text)

if match:
    print(match.group())  # 987-6543
```

## re.search() と re.compile() の違い

| 比較項目       | `re.search()`                        | `re.compile()`                          |
|----------------|--------------------------------------|-----------------------------------------|
| 役割           | 文字列の中にマッチするかを調べる    | 正規表現パターンを準備・再利用可能にする |
| 呼び方         | `re.search(パターン, 文字列)`        | `re.compile(パターン)` → `.search()` などで使用 |
| 再利用性       | 低い（1回限り）                     | 高い（複数文字列に繰り返し使える）      |
| パターンの管理 | その場で書く                         | 事前に変数として持つことができる         |

### 使い分けの目安

- **1回だけ検索したい場合** → `re.search()` でOK  
- **同じパターンを何度も使う** → `re.compile()` を使うとコードがすっきりして効率的

## 正規表現フラグの使い方

パターンに対してオプションを付けたいときは「フラグ」を指定できます。

| フラグ | 内容 |
|--------|------|
| `re.IGNORECASE` / `re.I` | 大文字・小文字を区別しない |
| `re.MULTILINE` / `re.M`  | `^`と`$`が各行に作用 |
| `re.DOTALL` / `re.S`     | `.` が改行にもマッチするようになる |

```python
pattern = re.compile(r"hello", re.IGNORECASE)

print(pattern.search("HELLO there"))  # マッチする
```

## まとめ

正規表現は最初は難しく見えますが、**よく使う記号と使い方を覚えてしまえば非常に強力なツール**になります。  
Pythonでは `re` モジュールを使って簡単に使い始められるので、パターン → 結果 → マッチオブジェクト の流れを意識して慣れていきたいです。

試験では次のようなポイントがよく問われます：

- `\d`, `\w`, `.` などの基本記号
- `{}` での繰り返し指定
- `re.search()` / `re.compile()` の使い分け
- `match.group()` や `match.span()` の使い方
- `re.IGNORECASE` などのフラグの意味

このまとめを活かして、正規表現に対する苦手意識を少しずつ減らしていきたいです。