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

时间:2014-10-21 18:40:22

标签: javascript regex

这是我的代码:

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修饰符,所以我看不出问题是什么,我该如何解决?

1 个答案:

答案 0 :(得分:6)

问题是您的模式与某个数字匹配,"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" />
&#13;
&#13;
&#13;

但是,在你走得更远之前我会提醒你。看起来这个问题最好用一个合适的解析器解决。查看jison以获取有助于构建解析器的良好资源。


我支持我之前关于正则表达式的有用性有限的警告,但这可能是一种更简单的方法,只要您确定输入的一般格式大致正确,你不要介意一些不必要的括号:

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

&#13;
&#13;
$('#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);
});
&#13;
<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" />
&#13;
&#13;
&#13;