Javascript-使用全局修饰符替换失败

Javascript - Replace using global modifier fails

本文关键字:替换 失败 全局 Javascript-      更新时间:2023-09-26

这是我的代码:

str = str.replace(/('+?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity))([%!]+)/g, function(m, $1,     $2) {
      return "(" + $1 + ")" + $2.replace(/%/g, ".percent()")
                                .replace(/!/g, ".fact()");
});
str = str.replace(/([+]?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity)|')|'%|'!)'^([-+]?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity)|'()/g, function(m, $1, $2) {
    if ($1 == ")" && $2 == "(") {
        return (").pow(");
    }
    if ($1 == "%" && $2 == "(") {
        return ("%.pow(");
    }
    if ($1 == "!" && $2 == "(") {
        return ("!.pow(");
    }
    if ($1 == ")") {
        return (").pow(" + $2 + ")");
    }
    if ($1 == "%") {
        return ("%.pow(" + $2 + ")");
    }
    if ($1 == "!") {
        return ("!.pow(" + $2 + ")");
    }
    if ($2 == "(") {
        return ("(" + $1 + ").pow(");
    }
    return ("(" + $1 + ").pow(" + $2 + ")");
});

问题是,我想替换所有出现的情况,但它不会这样做

"2%" -> "(2).percent()", working
"2%%" -> "(2).percent()%", should be "(2).percent().percent()"

我使用了g修饰符,所以我看不出问题是什么,我该如何解决这个问题?

问题是,您的模式匹配某个数字"Infinity"),后面跟着一个%,但第二个%前面没有这些数字,所以它根本不匹配。

看起来你希望通过在百分比之前匹配)符号,它会从你之前的替换中获得最后的),并将其作为下一次匹配的一部分。正则表达式引擎不是那样工作的。一旦找到匹配项,它将继续进行下一个匹配项。

换句话说,g修饰符的意思不是"递归替换替换,直到找不到匹配项",而是"替换原始字符串中找到的所有匹配项"。

我相信还有其他解决方案,但你可以试试这个:

str = str.replace(/('+?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity))(%+)/g, function(m, $1, $2) {
  return "(" + $1 + ")" + new Array($2.length + 1).join(".percent()");
});

考虑到你最新的问题,你可以这样做:

str = str.replace(/('+?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity))([%!]+)/g, function(m, $1, $2) {
  return "(" + $1 + ")" + $2.replace(/%/g, ".percent()")
                            .replace(/!/g, ".fact()");
});

给出您的第二次更新:

var re = /('+?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity))((?:[%!]|'^[+-]?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity|'())*)/g;
str = str.replace(
  re,
  function(m, $1, $2) {
    return "(" + $1 + ")" + $2.replace(/'^([^(^%!]+)/g, ".pow($1)")
                              .replace(/'^'(/g, ".pow(")
                              .replace(/%/g, ".percent()")
                              .replace(/!/g, ".fact()");
  });

$('#go').click(function() {
  var str = $("#input").val();
  var re = /('+?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity))((?:[%!]|'^[+-]?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity|'())*)/g;
  str = str.replace(
    re,
    function(m, $1, $2) {
      return "(" + $1 + ")" + $2.replace(/'^([^(^%!]+)/g, ".pow($1)")
                                .replace(/'^'(/g, ".pow(")
                                .replace(/%/g, ".percent()")
                                .replace(/!/g, ".fact()");
    });
    $("#output").text(str);
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="input" value="5!^3%" /><button id="go">Go</button>
<div id="output" />

然而,在你走得更远之前,我要提醒你。看起来这个问题最好用一个合适的解析器来解决。看看jison,可以找到一个很好的资源来帮助您构建解析器。


我坚持我之前关于正则表达式用处有限的警告,但这里有一种更简单的方法,你可以尝试,只要你确定输入的一般格式大致正确,并且你不介意几个不必要的括号:

str = str.replace(/[+-]?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity)/g, "($&)")
         .replace(/%/g, ".percent()")
         .replace(/!/g, ".fact()")
         .replace(/'^/g, ".pow");

$('#go').click(function() {
  var str = $("#input").val();
  str = str.replace(/[+-]?(?:(?:'d+'.?'d*|'.'d+)(?:e[+-]?'d+)?|Infinity)/g, "($&)")
           .replace(/%/g, ".percent()")
           .replace(/!/g, ".fact()")
           .replace(/'^/g, ".pow");
  $("#output").text(str);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="input" value="(2)^2!" /><button id="go">Go</button>
<div id="output" />