【JavaScript, 正規表現】replace()で複数文字列を置換した際のエラーについて


はじめに

  • 実行環境:Google Apps Script
  • 文字列 log(x) から Math.log(x) への置換

エラー内容

log(x) が1つの場合は問題なかったが、log(x) + log(y) のように複数になると一部しか置換されなかった。

js
function convertExpression(str){
  str = str.replace(/log\((.+)\)/g, "Math.log($1)");   
  console.log(str);  // Math.log(2) + log(3) ← 置換されていない
  return String(eval(str));
}

console.log(convertExpression("log(2) + log(3)"));  // ReferenceError: log is not defined

原因

基本的な正規表現一覧によると

+ : 直前の文字が 1回以上 繰り返す場合にマッチします。最長一致。条件に合う最長の部分に一致します。
+? : 直前の文字が 1回以上 繰り返す場合にマッチします。最短一致。条件に合う最短の部分に一致します。

つまり、最初のコードでは最長一致になっていたため、1つ目の ) はスルーされ、.+ の部分に 2) + log(3 がマッチした。それが Math.log() の中に入って Math.log(2) + log(3) となったようだ。

解決

.+ の部分を .+? にすることで解決した。

js
function convertExpression(str){
  str = str.replace(/log\((.+?)\)/g, "Math.log($1)");   
  console.log(str);  // Math.log(2) + Math.log(3) ← 置換された
  return String(eval(str));
}

console.log(convertExpression("log(2) + log(3)"));  // 1.791759469228055

参考