2019年11月27日

エスケープ, 特殊文字

これまで見てきたように、バックスラッシュ \ は文字クラスを表すのに使われます。例: \d。なので、正規表現の中では特別な文字です。

同様に他にも特殊文字があり、正規表現の中で特別な意味を持ちます。それらはよりパワフルな検索をするために使われます。

これがその完全なリストです: [ \ ^ $ . | ? * + ( ).

覚えようとする必要はありません – それぞれを個別に見ていく際に、自然と覚えていくでしょう。

エスケープ

特殊文字を通常の文字として使用するには、バックスラッシュを付加します。

それは “文字をエスケープする” とも言われます。

例えば、ドット '.' を探したいとします。正規表現でドットは “改行以外の任意の文字” を意味します。そのため、本当に “ドット” を意味する場合、前にバックスラッシュ \. を置きましょう。

alert( "Chapter 5.1".match(/\d\.\d/) ); // 5.1 (マッチ!)
alert( "Chapter 511".match(/\d\.\d/) ); // null (ドット) \. を探します)

括弧も特殊文字なので、それらを探したい場合は \( を使う必要があります。下の例は文字列 "g()" を探します:

alert( "function g()".match(/g\(\)/) ); // "g()"

バックスラッシュを探している場合は2つにします:

alert( "1\\2".match(/\\/) ); // '\'

スラッシュ

スラッシュ記号 '/' は特殊文字ではありませんが、JavaScript では正規表現の開始と終了で使われる(/...pattern.../)ので、これもエスケープが必要です。

スラッシュ '/' の検索は次のようになります:

alert( "/".match(/\//) ); // '/'

一方、/.../ ではなく new RegExp 構文を利用する場合、エスケープする必要はありません:

alert( "/".match(new RegExp("/")) ); // '/' が見つかります

new RegExp

new RegExp で正規表現を作成している場合、/ はエスケープする必要はありませんが、エスケープが必要なものもいくつかあります。

例えばこれを見てください:

let reg = new RegExp("\d\.\d");

alert( "Chapter 5.1".match(reg) ); // null

1つ前の類似の例は /\d\.\d/ が機能しましたが、new RegExp("\d\.\d") は機能しません。なぜでしょう?

理由は、バックスラッシュが文字列によって “消費される” ためです。覚えているかもしれませんが、通常の文字列文字列には \n などの独自の特殊文字があり、バックスラッシュはそのエスケープのために使用されます。

どのように “\d.\d” が受け取られるか:

alert("\d\.\d"); // d.d

引用符はバックスラッシュを “消費” して解釈します。例えば:

  • \n – は改行文字になります
  • \u1234 – はそのようなコードをもつユニコード文字になります
  • …そして特殊な意味を持たないもの、\d\z のようなものの場合には、バックスラッシュは単に除去されます。

したがって、new RegExp の呼び出しは、バックスラッシュのない文字列を取得します。

これを直すには、引用符で \\\ にするためにバックスラッシュを二重にする必要があります。:

let regStr = "\\d\\.\\d";
alert(regStr); // \d\.\d (正しい)

let reg = new RegExp(regStr);

alert( "Chapter 5.1".match(reg) ); // 5.1

サマリ

  • 特別な文字 [ \ ^ $ . | ? * + ( ) を文字通り検索するためには、バックスラッシュ \ を先頭に追加する必要があります(エスケープします)。
  • /.../ を利用する場合、\ もエスケープが必要です(new RegExpでは不要です)。
  • 文字列を new RegExp を渡すとき、文字列の引用符もバックスラッシュを消費するので、2つのバックスラッシュ \\ が必要です。
チュートリアルマップ