JavaScript,RegExp - 使用涉及标记表达式的评估表达式进行替换?

4

正则表达式可以使用所谓的标记表达式替换匹配的模式。

例如:

var s = "... some string with full things...";
s = s.replace(/(some|full)/gi, "\"aw$1\");

这将导致...
'... "awsome" string with "awfull" things...'

生活很棒,因为一些和充分相匹配,而$1在替换字符串中反映了大括号中匹配的标记表达式,在这种情况下——仅仅是一些或充分。

现在我们有了想法——我正在寻找一种实现以下操作的方法:

替换前的字符串:

"{timeOfEffect: 3*24*60*60 }"

之后的字符串

"{timeOfEffect: 259200}"

这些值的表示方式是由人类编辑的,以易于理解的术语呈现,例如(60秒*60分钟*24小时)*3 => 3天(别问,客户的要求),但在计算机术语中读作259200秒,并且可能包含许多该模式的出现。

我想尝试创建一个替换表达式,将$1和$2相乘,甚至将$1和$2传递给函数,或将$1 * $2传递给评估上下文,但我必须手动创建一个函数来实现它。

我得到的最接近的结果是

var x = /([0-9]*)\s\*\s([0-9]*)/g
  , r = function(m){
           return m[1] * m[2];
        }
while (m = x.exec(s))
  s = s.replace( x, r(m));

这有点糟糕,因为 exec 只返回第一个匹配项。 在替换语句中处理后,下一次搜索将从字符串的开头重新开始——该字符串长度为60K...

一个好的解决方案是以下之一: a)从索引开始执行匹配(而不创建新的子字符串) b)提供一个允许评估的替换表达式

另一种方法是将字符串进行分词,并逐个处理它们——这完全是对于RegExp的替代方案,但需要大量的代码和努力,如果这样的话,我只能接受性能损失或者寻找更好的替代方案来满足需求...

有人可以帮忙吗?

2个回答

7
var s = "timeOfEffect: 3*24*60*60 var: 6*8 ";
var r = new RegExp("([0-9*+-/]{0,}[0-9])","g");
s = s.replace(r,function(match){ return eval(match); });
alert(s)

哇,这个很酷!稍微调整一下正则表达式,它就可以涵盖所有基本的算术运算(假设它们在语法上是正确的)!- 棕色巫师Radagast 0秒前编辑 - Radagast the Brown
1
好的,这是最终解决方案。 它可以轻松扩展以支持大括号,但我不需要。原始提供的问题在于它也匹配了简单的数字 - 这些数字不需要替换。 var r = new RegExp("([0-9\\.]+)([\\*+-\\/].)([0-9\\*+-\\/]+)([0-9])","g"); r = function(m,m1,m2,m3,m4){ try{ return ":" + eval(m1+m2+m3+m4) }catch(ex){ return ":\"@@EVAL_ERROR:" + m1+m2+m3+m4 + "\"" } } } s = s.replace(x,r)输出显然会被检查是否包含 "@@EVAL_ERROR" 并发送邮件报告配置错误...谢谢 :) - Radagast the Brown
嘿,酷酷的!match函数的倒数第二个参数是搜索字符串中匹配项的索引,最后一个参数是整个搜索字符串本身!!而且它非常快!我可以使用它向编辑器发出准确的解析错误!! :) - Radagast the Brown

5
var str = '{timeOfEffect: 3*24*60*60}, {timeOfEffect: 1+7}, {timeOfEffect: 20-3}, {timeOfEffect: 3 / 0}';

var result = str.replace(/\s([\d\/\*\-\+\s]+?)\}/g, function(all, match) {
    return eval(match) + '}';
});

document.body.innerHTML = result;
// {timeOfEffect:259200}, {timeOfEffect:8}, {timeOfEffect:17}, {timeOfEffect:Infinity}

jsFiddle

eval() 是安全的,因为我们已经确保字符串只包含 0-9, , \n, \t, /, *, -+我曾经希望 会有类似 Math.parse() 的东西,但是没有。

如果你需要更复杂的需要括号的数学运算,只需将转义的 () 添加到正则表达式字符范围中即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接