JavaScriptの正規表現 各メソッド(ローカル/グローバル) 昔まとめたリスト

この記事はChrome55でいろいろ試行錯誤した時のメモ
同様の記事はいっぱいあるはず

使用頻度の高そうなグローバル正規表現 g オプションフラグをメインに
**意図していなかった処理を行いそう**な動作が気になったので各メソッドで動作を調べた

# RegExpとStringの正規表現関係メソッド

### RegExpオブジェクトのメソッド

```js
regexp.test(string)
regexp.exec(string)
```

### Stringオブジェクトのメソッド

```js
string.match(regexp)
string.search(regexp)
string.split(regexp)
string.replace(regexp)
```

# 正規表現パターン

| パターン | 説明 |
|---|---|
| /abc/ | "abc" にマッチ |
| /[abc]/ | "a" か "b" か "c" にマッチ |
| /[a-c]/ | "a" から "c" にマッチ |
| /[^abc]/ | "a" でも "b" でも "c" でもない文字にマッチ |
| /^abc/ | ローカル正規表現では文字列の頭を表し、グローバルでは行頭を表す |
| /abc$/ | ローカル正規表現では文字列の尻を表し、グローバルでは行末を表す |
| /a?/ | 0回か、1回だけ出現する |
| /a+/ | 1回以上繰り返し |
| /a*/ | 0回以上繰り返し |
| /a{5}/ | 5回の繰り返し |
| /a{5,10}/ | 5回以上10回以下の繰り返し |
| /a{5,}/ | 5回以上の繰り返し |
| 控えめなマッチ | 繰り返し演算子は最大数マッチしようとするが<br>? を付けることにより最小限のマッチで済まそうとする <br>"abcabcab".match(/a.\*c/)<br>=> ["abcabc"]<br>"abcabcab".match(/a.\*?c/)<br>=> ["abc"] |
| /(ab)/ | 文字列のグループ化 副次効果でキャプチャも行う |
| /(?:ab)/ | 文字列のグループ化 キャプチャを行わない |
| /a(?=b)/ | bが続くaにマッチ（肯定的先読み） |
| /a(?!b)/ | b以外が続くaにマッチ（否定的先読み） |
| /(?<=b)a/ | bに続くaにマッチ（肯定的後読み） |
| /(?<!b)a/ | b以外に続くaにマッチ（否定的後読み） |
| /\t/ | タブ |
| /\r/ | キャリッジリターン |
| /\f/ | ラインフィード |
| /\n/ | 改行 |
| /\uxxxx/<br>/\u{xxxx}/u | ユニコード文字 |
| /./ | **改行以外**のあらゆる文字<br>~~（.を改行にマッチさせる方法はJavaScriptには無い）~~<br>[ES2018]でsオプションが追加された|
| /\d/ | [0-9] すべての数字 |
| /\D/ | [^0-9] 数字以外のあらゆる文字 |
| /\w/ | [A-Za-z0-9] すべての英数字 |
| /\W/ | [^A-Za-z0-9] 英数字以外のあらゆる文字 |
| /\s/ | ユニコード空白文字(スペース, 全角スペース, タブ, 改行 等) |
| /\S/ | ユニコード空白文字以外のあらゆる文字 |
| /\b/ | 単語の境界にマッチする(スペース、句読点 等) |
| /\B/ | /b の逆 |
| /moko&#124;hage/ | moko か hage  |
| /moko(A&#124;B)/ | mokoA か mokoB （カッコは副次効果でキャプチャも生成する） |
| /moko(?:A&#124;B)/ | mokoA か mokoB （キャプチャを生成しない） |
| /moko(A&#124;B)hage\1/ | mokoAhageA か mokoBhageB （キャプチャを後方参照する） |
| \$1, \$2, \$3... | 変換後文字にて後方参照を指定する（キャプチャを利用する） |
| $& | 変換後文字にて後方参照を指定する（マッチ文字列） |

# 正規表現オブジェクトの作り方

```js
const regexp1 = new RegExp("[AB]0[12]", 'gmi');
```

# 正規表現リテラルでも記述できる

ていうか通常こっちを使っているとは思いますが

```js
const regexp2 = /[AB]0[12]/;
const regexp3 = /[AB]0[12]/gmi;
```

# 使いそうな正規表現オプションフラグ

#### g

- global
- 検索文字列全体について繰り返して一致を検索する
- グローバルじゃない方はローカル正規表現と言っている書籍も有ったんでそう呼んでます

#### i

- ignoreCase
- 大文字と小文字の違いを無視

#### m

- multiline
- 行をまたいだ検索を行う

#### u

[ES2015]で追加されたぞらしいぞ！
使わない理由は無いように思えるぞ！

# 使いそうな正規表現オブジェクトのプロパティ

#### lastIndex

グローバル正規表現時に次のマッチが始まる位置を保持している

#### source

フラグ無しの正規表現パターンを格納している => "[AB]"

# regexp#test(string)

マッチするかどうかが知りたいだけならこれ

```js
// ローカル正規表現
const regexp4 = /moko\d+/

regexp4.test("moko123 moko456")
// => true
```

```js
// グローバル正規表現
const regexp5 = /moko\d+/g;

regexp5.test("moko123 moko456")
// => true
```

グローバル正規表現オブジェクトはlastIndexを保持しているので、同メソッドを繰り返し実行すると結果に違いが出てくる

```js
regexp4.lastIndex
// => 0
regexp5.lastIndex
// => 7

regexp4.test("moko123 moko456")
// => true
regexp5.test("moko123 moko456")
// => true

regexp4.lastIndex
// => 0
regexp5.lastIndex
// => 15

regexp4.test("moko123 moko456")
// => true
regexp5.test("moko123 moko456")
// => false <== マッチしない

regexp4.lastIndex
// => 0
regexp5.lastIndex
// => 0 <== リセットされた

regexp4.test("moko123 moko456")
// => true
regexp5.test("moko123 moko456")
// => true <== またマッチするようになった
```

こんな使い方をした事はないけど、予想外の動作をする可能性がある

```js
const regexp6 = /moko\d+/g;

regexp6.test("moko123")
// => true

regexp6.test("moko456")
// => false <== あー
```

### regexp#test(string) ではグローバル正規表現を使わない方がいいぞ！

# regexp#exec(string)

マッチオブジェクト(プロパティを持った配列)が取得できる
マッチしなかった場合はnullが返ってくる

```js
// ローカル正規表現
const regexp7 = /moko\d+/

regexp7.exec("moko123 moko456")
// => ["moko123", index: 0, input: "moko123 moko456"]

regexp7.exec("moko123 moko456")
// => ["moko123", index: 0, input: "moko123 moko456"] <== 何度実行しても戻り値は変わらない

regexp7.exec("")
// => null
```

```js
// グローバル正規表現
const regexp8 = /moko\d+/g

regexp8.exec("moko123 moko456")
// => ["moko123", index: 0, input: "moko123 moko456"]

regexp8.exec("moko123 moko456")
// => ["moko456", index: 8, input: "moko123 moko456"] <== おっ

regexp8.exec("moko123 moko456")
// => null <== えっ

regexp8.exec("moko123 moko456")
// => ["moko123", index: 0, input: "moko123 moko456"] <== あっ

regexp8.exec("")
// => null
```

キャプチャしている場合、キャプチャのカッコ部分にマッチした部分も配列内に配置される

```js
// ローカル正規表現
const regexp9 = /moko(\d+)/

regexp9.exec("moko123 moko456")
// => ["moko123", "123", index: 0, input: "moko123 moko456"]

regexp9.exec("moko123 moko456")
// => ["moko123", "123", index: 0, input: "moko123 moko456"] <== 何度実行しても戻り値は変わらない
```

```js
// グローバル正規表現
const regexp10 = /moko(\d+)/g

regexp10.exec("moko123 moko456")
// => ["moko123", "123", index: 0, input: "moko123 moko456"]

regexp10.exec("moko123 moko456")
// => ["moko456", "456", index: 8, input: "moko123 moko456"] <== おっ

regexp10.exec("moko123 moko456")
// => null <== えっ

regexp10.exec("moko123 moko456")
// => ["moko123", "123", index: 0, input: "moko123 moko456"] <== あっ
```

### regexp#exec(string) ではグローバル正規表現は便利だが注意が必要だ！

# string#match(regexp)

ローカル正規表現の場合、マッチオブジェクト(プロパティを持った配列)が取得できる
マッチしなかった場合はnullが返ってくる

```js
// ローカル正規表現
const regexp11 = /moko(\d+)/

"moko123 moko456".match(regexp11)
// => ["moko123", "123", index: 0, input: "moko123 moko456"]

"moko123 moko456".match(regexp11)
// => ["moko123", "123", index: 0, input: "moko123 moko456"] <== 何度実行しても戻り値は変わらない

"".match(regexp11)
// => null
```

グローバル正規表現の場合、マッチした文字列を集めた配列が取得できる
戻り値にキャプチャは影響を与えない
正規表現オブジェクトは引数なので変更されたりしないのか、lastIndexも気にしなくていいぽい
マッチしなかった場合は空配列ではなくnullが返ってくる

```js
// グローバル正規表現
const regexp12 = /moko(\d+)/g

"moko123 moko456".match(regexp12)
// => ["moko123", "moko456"]

"moko123 moko456".match(regexp12)
// => ["moko123", "moko456"] <== 何度実行しても戻り値は変わらない

"".match(regexp12)
// => null <== うーん
```

### string#match(regexp) ではローカル正規表現もグローバル正規表現も、両方便利なものだ！

# string#search(regexp)

文字列にマッチした位置(index)が取得できる
戻り値にキャプチャは影響を与えない
正規表現オブジェクトは引数なので変更されたりしないのか、lastIndexも気にしなくていいぽい
つまりローカル正規表現とグローバル正規表現を使い分ける意味はなさそう
マッチしなかった場合は-1が返ってくる

```js
// ローカル正規表現
const regexp13 = /moko(\d+)/ // 敢えてキャプチャを指定しています

"moko moko456".search(regexp13)
// => 5

"moko moko456".search(regexp13)
// => 5 <== 何度実行しても戻り値は変わらない

"".search(regexp13)
// => -1
```

```js
// グローバル正規表現時
const regexp14 = /moko(\d+)/g // 敢えてキャプチャを指定しています

"moko moko456".search(regexp14)
// => 5

"moko123 moko456".search(regexp14)
// => 5 <== 何度実行しても戻り値は変わらない

"".search(regexp14)
// => -1
```

### string#search(regexp) ではグローバル正規表現を使うメリットは無いぞ！

# string#split(regexp)

マッチした箇所で文字列を分割して配列を返す
戻り値にキャプチャは影響を与えな・・与える。ていうか**予想外の動作になる**ので注意
正規表現オブジェクトは引数なので変更されたりしないのか、lastIndexも気にしなくていいぽい
つまりローカル正規表現とグローバル正規表現を使い分ける意味はなさそう

```js
// ローカル正規表現
const regexp15 = /\d+/ // キャプチャなし

"a1b23c4d".split(regexp15)
// => ["a", "b", "c", "d"]

"a1b23c4d".split(regexp15)
// => ["a", "b", "c", "d"] <== 何度実行しても戻り値は変わらない
```

```js
// ローカル正規表現
const regexp16 = /(\d+)/ // キャプチャ

"a1b23c4d".split(regexp16)
// => ["a", "1", "b", "3", "c", "4", "d"] <== えっ

"a1b23c4d".split(regexp16)
// => ["a", "1", "b", "3", "c", "4", "d"] <== 何度実行しても戻り値は変わらない
```

```js
// ローカル正規表現
const regexp17 = /(?:\d+)/ // キャプチャ無効

"a1b23c4d".split(regexp17)
// => ["a", "b", "c", "d"]

"a1b23c4d".split(regexp17)
// => ["a", "b", "c", "d"] <== 何度実行しても戻り値は変わらない
```

```js
// グローバル正規表現
const regexp18 = /\d+/g // キャプチャなし

"a1b23c4d".split(regexp18)
// => ["a", "b", "c", "d"]

"a1b23c4d".split(regexp18)
// => ["a", "b", "c", "d"] <== 何度実行しても戻り値は変わらない
```

```js
// グローバル正規表現
const regexp19 = /(\d+)/g // キャプチャ

"a1b23c4d".split(regexp19)
// => ["a", "1", "b", "3", "c", "4", "d"] <== えっ

"a1b23c4d".split(regexp19)
// => ["a", "1", "b", "3", "c", "4", "d"] <== 何度実行しても戻り値は変わらない
```

```js
// グローバル正規表現
const regexp20 = /(?:\d+)/g // キャプチャ無効

"a1b23c4d".split(regexp20)
// => ["a", "b", "c", "d"]

"a1b23c4d".split(regexp20)
// => ["a", "b", "c", "d"] <== 何度実行しても戻り値は変わらない
```

### string#split(regexp) ではグローバル正規表現を使うメリットは無いぞ！
### string#split(regexp) ではキャプチャは使うな！

# string#replace(regexp, string)

文字列にマッチした箇所を置換する
ローカル正規表現時は最初にマッチした箇所のみ、グローバル正規表現字は全てのマッチした箇所が対象
戻り値にキャプチャは影響を与えない
正規表現オブジェクトは引数なので変更されたりしないのか、lastIndexも気にしなくていいぽい

```js
// ローカル正規表現
const regexp21 = /moko\d+/

"moko123 moko456".replace(regexp21, "hage")
// => "hage moko456"

"moko123 moko456".replace(regexp21, "hage")
// => "hage moko456" <== 何度実行しても戻り値は変わらない
```

```js
// グローバル正規表現
const regexp22 = /moko\d+/g

"moko123 moko456".replace(regexp22, "hage")
// => "hage hage"

"moko123 moko456".replace(regexp22, "hage")
// => "hage hage" <== 何度実行しても戻り値は変わらない
```

## オマケ 後方参照系を利用して置換してみる

\$1, \$2 はキャプチャ箇所がそれぞれに置換されるんでしたね

```js
// ローカル正規表現
const regexp23 = /moko([13])/

"moko1 moko2 moko3".replace(regexp23, "hage$1")
// => "hage1 moko2 moko3"

"moko1 moko2 moko3".replace(regexp23, "hage$1")
// => "hage1 moko2 moko3" <== 何度実行しても戻り値は変わらない
```

```js
// グローバル正規表現
const regexp24 = /moko([13])/g

"moko1 moko2 moko3".replace(regexp24, "hage$1")
// => "hage1 moko2 hage3"

"moko1 moko2 moko3".replace(regexp24, "hage$1")
// => "hage1 moko2 hage3" <== 何度実行しても戻り値は変わらない
```

$& はマッチ箇所全体に置換されるんでしたね

```js
// ローカル正規表現
const regexp25 = /moko[13]/

"moko1 moko2 moko3".replace(regexp25, "hage_$&")
// => "hage_moko1 moko2 moko3"

"moko1 moko2 moko3".replace(regexp25, "hage_$&")
// => "hage_moko1 moko2 moko3" <== 何度実行しても戻り値は変わらない
```

```js
// グローバル正規表現
const regexp26 = /moko[13]/g

"moko1 moko2 moko3".replace(regexp26, "hage_$&")
// => "hage_moko1 moko2 hage_moko3"

"moko1 moko2 moko3".replace(regexp26, "hage_$&")
// => "hage_moko1 moko2 hage_moko3" <== 何度実行しても戻り値は変わらない
```

### string#replace(regexp) ではローカル正規表現もグローバル正規表現も、両方便利なものだ！

# string#replace(regexp, function(f, s, s+1, ..., n-2, n-1, n) {})

string#replace()は第2引数に functionも受け付ける
つまり、コールバック関数の戻り値を利用して置換するということ
コールバック関数の引数は可変長になる

- f マッチした文字列
- s キャプチャ その1
- s+1 キャプチャ その2
- n-2 キャプチャ 最後
- n-1 マッチ位置
- n 検索対象文字列全て

```js
// ローカル正規表現
const regexp27 = /(moko)(\d+)/

"moko123 moko456".replace(regexp27, function() {
  console.log(arguments);
  return arguments[1] + (parseInt(arguments[2], 10) * 2);
})

// => ["moko123", "moko", "123", 0, "moko123 moko456"]
// => "moko246 moko456"
```

```js
// グローバル正規表現
const regexp28 = /(moko)(\d+)/g

"moko123 moko456".replace(regexp28, function() {
  console.log(arguments);
  return arguments[1] + (parseInt(arguments[2], 10) * 2);
})

// => ["moko123", "moko", "123", 0, "moko123 moko456"]
// => ["moko456", "moko", "456", 8, "moko123 moko456"]
// => "moko246 moko912"
```

### string#replace(regexp, function() {}) ではローカル正規表現もグローバル正規表現も、両方便利なものだ！