テクデップ(Techdep)

コンピュータ、プログラミング、DTP(InDesign)に関する備忘録

エスケープシーケンスは二度死ぬ

JavaScriptにおいて、変数を利用して柔軟な正規表現処理を実施したいときは、

var tag = "aieeeee";
str.replace(new RegExp(tag, "g"), convertedText);

の様にRegExpコンストラクタを呼び出せば良い。

さて、ここでLaTeX記法の様な「\section」から始まる文字列を正規表現で置換したいとする。変数tagにはどう代入すれば良いか?

解答

解答としては次の様になる。

var tag = "\\\\section";
str.replace(new RegExp(tag, "g"), convertedText);

解説

変数を使用しない正規表現の感覚で、

str.replace("\\section", convertedText);

の様に変数tagに、

var tag = "\\section";
str.replace(new RegExp(tag, "g"), convertedText);

と代入しては「\section」は正規表現で拾われない。

これは、バックスラッシュは特殊文字であるからエスケープ処理をせねばならないが、この処理が二度行われるからである。まず、tagに代入処理があるときにエスケープ処理があるから、\\sectionが格納される。そして、RegExpコンストラクタを呼び出したときに再びエスケープ処理がされるので、\\sectionは\sectionになる。バックスラッシュのカルテットで、漸く望み通りの正規表現処理が実現されるわけだ*1

尚、変数を経由せずにコンストラクタに文字列を渡すときも同様である。

str.replace(new RegExp("\\\\" + tag, "g"), convertedText);

*1:LaTeXのタグ類を一括で正規表現処理しようとして外部変数で定義したものの、エスケープ処理が一回しかされないと誤解して実装したため期待通りの動作をせず数日間悩んだ。