LoginSignup
42
36

More than 3 years have passed since last update.

JavaScriptでの正規表現のハマりポイント

Last updated at Posted at 2014-05-02

以前ハマったので、メモとして書いておきます。

"." は改行文字にマッチしないし、マッチさせるすべがない(ES2018より以前)

(この JavaScript は ES2018 より以前を想定しています)

var container = document.getElementById("container");
container.innerHTML = container.innerHTML.replace(/===ここから===.*?===ここまで===/, "");

これ、「===ここから===」と「===ここまで===」が一行に収まっていればマッチするのですが、複数行にまたがっている場合にはマッチしませんし、当然置換も行われません。 ドットが改行文字にマッチしないから です。

記事 RegExp - JavaScript | MDN によると、修飾子(flag) には g i m y があるのですが、Perlでドットを改行文字にマッチさせる s 修飾子というものがないので、どうしようもありません(ES2018については後述)。

上述のページにも "." の説明がこう書かれています。

(この文字は小数点です) 改行文字(\n\r\u2028、あるいは、\u2029)を除いたあらゆる 1 文字にマッチします( [\s\S] という正規表現を使えば、改行文字を含めたあらゆる文字にマッチさせることができます)。

というわけで、上記のJavaScriptは以下のように書き換えることで、複数行マッチにも対応することができます。

var container = document.getElementById("container");
container.innerHTML = container.innerHTML.replace(/===ここから===[\s\S]*?===ここまで===/, "");

なお、ES2018 では晴れて s 修飾子が追加されました。RegExp - JavaScript | MDN の記事にも2019年春に s への言及が追加されています

"^" はどんな場所でもメタ文字のように振る舞う

正規表現の ^

  • 正規表現の冒頭にある場合には、冒頭から開始するという意味
  • 文字クラス ([] で囲われたもの) の先頭にあると、文字クラスの集合の補集合となる

という意味でメタ文字として使われますが、その他の場所ではそれを書いたとしても書いていないようにみなされてしまいます。

(※当初、PerlやPCREでは上記以外のような場所では ^ はその文字自身を表すと書きましたが、間違っていました)

// Chrome デベロッパーコンソールで実験
> str1 = "abc^def"
"abc^def"
> str1.match(/c^d/)
null

この現象を回避して ^ をその文字自身としてマッチさせるには、\ でエスケープをする必要があります。

> str1.match(/c\^d/)
["c^d"]
> re = new RegExp("c\\\\^d") // バックスラッシュ2つ
/c\^d/
> str1.match(re)
["c^d"]

とはいえ、^ を改行の直後にゼロ幅マッチさせるためには、m 修飾子を指定してやる必要があります。

> str2 = "xyz\n123"
"xyz
123"
> str2.match(/^1/)
null
> str2.match(/^1/m)
["1"]
42
36
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
36