正規表現入門＋α

## この記事のモチベーション

いろいろな業務で部下や後輩に正規表現の書き方について説明しており、毎回整理するのが大変だったため、いつでもどこでも参照できるように公開することにしました。

一般的な説明に、プラスアルファで実業務で間違いやすいポイントを補足しています。

## 正規表現とは

正規表現は、文字列のパターンを記述するための強力なツールです。テキスト検索、置換、データ検証など、多くのプログラミング言語やツールで広く使用されています。正規表現の基本的な文法を理解することは、その強力な機能を効果的に活用するための第一歩です。

### 免責事項

複数行にまたがる（改行文字を含む）パターンを記述できるかどうかは、環境やツールに大きく依存します。記事の内容の単純化のため、この記事では 1 行の（改行文字を含まない）パターンを前提に説明します。

## 基本文法

### リテラル

- **リテラル文字**: 通常の文字は、その文字自体に一致します。例えば、`a` は文字 `a` に一致します。

### 特殊文字

- **ドット(`.`)**: 任意の一文字に一致します。
- **バックスラッシュ(`\`)**: 特殊文字をエスケープするために使用されます。例えば、`\.`はピリオド自体に一致します。

### キャラクタクラス

- **`[...]`**: 指定された任意の文字に一致します。例えば、`[abc]`は `a`、`b`、`c` のいずれか 1 文字に一致します。
- **`[^...]`**: 指定された文字以外の任意の文字に一致します。例えば、`[^abc]`は `a`、`b`、`c` ではない任意の文字に一致します。

詳しくは別章に後述します。

### 量指定子

- **`*`**: 直前の要素の 0 回以上の繰り返しに一致します。
- **`+`**: 直前の要素の 1 回以上の繰り返しに一致します。
- **`?`**: 直前の要素の 0 回または1回の出現に一致します。
- **`{n}`**: 直前の要素の n 回の繰り返しに一致します。
- **`{n,}`**: 直前の要素の n 回以上の繰り返しに一致します。
- **`{n,m}`**: 直前の要素の n 回以上、 m 回以下の繰り返しに一致します。

たとえば、`colou?r` は、`color` または `colour` のいずれかの文字列に一致します。`GRe{4,}N` は、`GReeN` には一致しませんが、`GReeeeN`、`GReeeeeeN`、`GReeeeeeeeeeeeeeeeeeN` に一致します。

### 位置指定子

- **`^`**: 文字列の（行の）開始に一致します。
- **`$`**: 文字列の（行の）終了に一致します。

たとえば、`^her` は、`here` に一致しますが `there` には一致しません。`the$` は `breathe` に一致しますが `there` には一致しません。

なお、 `^` および `$` は複数行の文字列では環境依存することがあります（多くの場合は改行文字に一致しますが、保証できません）。免責事項をご参照ください。

### 論理演算子

- **`|`**: OR条件を表します。

例えば、`a|b` は `a` または `b` に一致します。

### グループ化

- **`( )`**: グループを作成します。グループ化された部分は、キャプチャグループとして扱われ、後から参照することができます。

たとえば、あるテキスト内で日付の形式を「YYYY-MM-DD」から「MM/DD/YYYY」に変換（置換）したいとします。グループ化を使って各部分を捕捉し、置換の際に参照できます。

```regex
([0-9]{4})-([0-9]{2})-([0-9]{2})
```

この正規表現は、4桁の年、2桁の月、2桁の日というパターンを検索し、それぞれをグループ化しています。置換操作を行う際には、これらのグループを参照して新しい形式に並べ替えます。多くのプログラミング言語やツールでは、`\1`、`\2`、`\3` のようにして各グループを参照できます。したがって、置換パターンは `\2/\3/\1` となり、これにより日付の形式を変更できます。

### 特殊文字のエスケープ

前述の通り、一部の文字は特殊な意味を持っています。これらの文字を単なる文字（リテラル）として検索したい場合は、バックスラッシュ(`\`)を前に置いてエスケープする必要があります。エスケープが必要な主な文字は以下の通りです。

- **`.`**：任意の一文字
- **`^`**：文字列（行）の開始
- **`$`**：文字列（行）の終了
- **`*`**：直前の文字の 0 回以上の繰り返し
- **`+`**：直前の文字の 1 回以上の繰り返し
- **`?`**：直前の文字の 0 回または 1 回の出現
- **`|`**：論理和
- **`\`**：エスケープ文字そのもの
- **`{`**, **`}`**：回数を指定した繰り返しに利用する
- **`[`**, **`]`**：キャラクタクラスに利用する
- **`(`**, **`)`**：グループ化に利用する

特に、`.` のエスケープを忘れないように注意しましょう。`.` が意味する「任意の一文字」には `.` 文字そのものも含まれるため、**もしエスケープを忘れても一致する** というミスを誘発しやすい特徴があります。

`foo.example.com` の文字列に一致させたい場合、`foo\.example\.com` のように記述します（後述しますが、別解として `foo[.]example[.]com` のような記述方法もあります）。

## キャラクタクラス

キャラクタクラスは複雑のため別項目としました。

### キャラクタクラスの基本説明
正規表現のキャラクタクラスは、特定の 1 文字を表すために使用されます。文字の集合が大括弧（`[]`）で囲まれます。キャラクタクラス内で指定されたどの一文字にも一致することができます。

たとえば、正規表現 `[abc]` は、「a」、「b」、「c」のいずれか一文字に一致します。

キャラクタクラスの中では、特定の文字範囲をハイフン（`-`）を使って指定することができます。例えば、`[a-z]` は任意の小文字のアルファベットに一致し、`[0-9]` は任意の一桁の数字に一致します。

以下はキャラクタクラスの使用例としてよく見られるパターンです：

- **`[A-Za-z]`**：任意の大文字または小文字のアルファベット一文字に一致します。
- **`[0-9]`**：任意の一桁の数字に一致します。
- **`[A-Za-z0-9]`**：任意のアルファベット（大文字または小文字）または数字に一致します。

注意すべきなのは、ここでいう「文字範囲」は、**[ASCII コード表](https://e-words.jp/p/r-ascii.html) の数字の大小で判断される**という点です。たとえば、大文字の `Z` と小文字の `a` は ASCII コード上で連続していません。したがって、任意のアルファベット一文字に一致させたい場合に `[A-z]` と記載してはいけません。ASCII コード上で `Z` と `a` の間にあるいくつかの文字にも一致してしまうからです。

### キャラクタクラスにおける特殊文字

キャラクタクラス内では、いくつかの特殊文字（`^`、`-`、`]`、`\`）が特別な意味を持ちます。これらの文字を文字として扱いたい場合は、バックスラッシュ（`\`）を使用してエスケープする必要があります。

- **`^`**：キャラクタクラスの最初に置かれた場合、否定のキャラクタクラスを作成します。例えば、`[^0-9]` は数字以外の任意の文字に一致します。
- **`-`**： 前述のとおり、範囲を指定するために使用されます。たとえば、`[0-9]` が任意の数字に一致します。
- **`]`**：キャラクタクラスを閉じるために使用します。
- **`\`**：バックスラッシュ自体も特別な意味を持ちます（エスケープ文字として）。

なお、**この 4 文字以外は特殊な意味を持ちません**。たとえば、`.` や `*` などの正規表現そのもので特殊文字として扱われる文字でも、キャラクタクラスの中では単なる文字として扱われます。たとえば、`[.*]` は `.`、`*` のいずれかに一致します（任意の文字に一致するものではありません）。

### 特殊文字のエスケープ

キャラクタクラスにおける特殊文字を、特殊な意味を持たせずに文字そのものとして扱いたい場合、以下のようにします。

- `^`：キャラクタクラスの最初以外に置けば普通の文字として扱われます。たとえば `[a^b]` は `a`、`^`、`b` のいずれかに一致します。 
- `-`： キャラクタクラスの最初か最後のどちらかに置けば普通の文字として扱われます。たとえば `[-ab]` や  `[ab-]` は `a`、`b`、`-` のいずれかに一致します。 
- `]`：エスケープしてください。たとえば `[ab\]]` は `a`、`b`、`]` のいずれかに一致します 
- `\`：エスケープしてください。たとえば `[ab\\]` は `a`、`b`、`\` のいずれかに一致します。