綺麗に死ぬITエンジニア

JavaScriptで正規表現文字列をエスケープする方法

2017-02-17

JavaScriptで正規表現を利用する際、生成したRegExpオブジェクトが思いどおりに動かない場合があります。

それは、もしかしたら正規表現で利用する特別な文字列がエスケープされていないのが原因かもしれません。

時々、正規表現へ動的な文字列を突っ込みたくなる時があるので、備忘録として正規表現文字列をエスケープする方法を記載します。

利用ケース

JavaScriptで文字列を正規表現RegExpを使って検索する場合、検索したい文字列に正規表現で利用する特別な文字が含まれていると正しく検索できません。

例えば、以下のような場合です。

var searchText = '詳しくは[こちら](https://s8a.jp/?tag=JavaScript)。';
var url = 'https://s8a.jp/?tag=JavaScript';

var regexp = new RegExp(url);

regexp.test(searchText);
// false

変数searchTextに変数urlの文字列が含まれているにも関わらず、test()関数の結果がfalseとなってしまいます。

このように.?などのエスケープが必要な文字が含まれていると、意図したとおりに動かないことがあります。

このような場合にエスケープが必要となります。

特に利用者によって変動する変数の場合、エスケープ処理は必須です。テスト時に漏れやすい項目なので、注意しましょう。

正規表現文字列をエスケープする

実際にエスケープする方法です。

きちんと関数を定義する場合は、以下の関数を定義しましょう。性能面ではこちらが有利です。

(function (w) {
    var reRegExp = /[\\^$.*+?()[\]{}|]/g,
        reHasRegExp = new RegExp(reRegExp.source);

    function escapeRegExp(string) {
        return (string && reHasRegExp.test(string))
            ? string.replace(reRegExp, '\\$&')
            : string;
    }

    w.escapeRegExp = escapeRegExp;
})(window);

これでグローバル関数escapeRegExp()へエスケープしたい文字列を渡すことで、エスケープされて返ってきます。

escapeRegExp('https://s8a.jp/?tag=JavaScript');
// "https://s8a\\.jp/\\?tag=JavaScript"

ワンライナーでサクッと実装したい場合は、以下のようにしましょう。

var string = 'https://s8a.jp/?tag=JavaScript';

string.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
// "https://s8a\\.jp/\\?tag=JavaScript"

これらの処理を間に挟むことで、検索したい文字列がエスケープされて正しく結果を取得できるようになります。

var searchText = '詳しくは[こちら](https://s8a.jp/?tag=JavaScript)。';
var url = 'https://s8a.jp/?tag=JavaScript';

var regexp = new RegExp(escapeRegExp(url));
// もしくは
// var regexp = new RegExp(url.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'));

regexp.test(searchText);
// true

まとめ

この辺りは、テスト時には入力しなかった値が入力される(テストの不備)等で、後からバグが判明しやすいところです。正規表現を扱う際は、しっかりと注意しましょう。