一些正则表达式模式打破了javascript正则表达式引擎

时间:2016-08-09 21:10:18

标签: javascript regex

我写了以下正则表达式:/\D(?!.*\D)|^-?|\d+/g

我认为应该这样:

\D(?!.*\D)    # match the last non-digit
|             # or
^-?           # match the start of the string with optional literal '-' character
|             # or
\d+           # match digits

但是,它没有:

var arrTest = '12,345,678.90'.match(/\D(?!.*\D)|^-?|\d+/g);
console.log(arrTest);

var test = arrTest.join('').replace(/[^\d-]/, '.');
console.log(test);

但是,在Regex101在线播放 PCRE(php) - 味道时。它像我描述的那样工作。

我不知道我是否认为它应该以某种方式起作用。或者如果javascript regex-flavor中有一些模式不允许。

2 个答案:

答案 0 :(得分:3)

JS与PCRE的工作方式不同。关键是JS正则表达式引擎不能很好地处理零长度匹配,索引只是手动递增,并且跳过零长度匹配后的下一个字符。 ^-?可以匹配空字符串,并且匹配12,345,678.90开头,跳过1

如果我们查看String#match documentation,我们会看到每次使用全局正则表达式调用match都会在零长度<之后增加正则表达式对象的lastIndex找到/ em>匹配:

  
      
  1. 否则,全球 true
      一个。使用参数“ lastIndex ”和0来调用rx的[[Put]]内部方法   湾设A是一个新的数组,就像表达式 new Array()一样,其中数组是具有该名称的标准内置构造函数。
      C。设 previousLastIndex 为0   d。设 n 为0   即让 lastMatch true
      F。重复,而 lastMatch true
      一世。设结果是使用 rx 调用 exec 的[[Call]]内部方法的结果 this 包含 S 的值和参数列表   II。如果结果 null ,则将 lastMatch 设置为 false
      III。否则,结果不是 null
      1.让 thisIndex 成为使用参数“ lastIndex ”调用 rx 的[[Get]]内部方法的结果。
      2.如果 thisIndex = previousLastIndex 则为
      一个。使用参数“ lastIndex ”和 thisIndex + 1 调用 rx 的[[Put]]内部方法。
      湾将 previousLastIndex 设置为 thisIndex +1。
  2.   

因此,匹配过程从 8a 8f 初始化辅助结构,然后输入while块(重复直到 lastMatch true ,内部 exec 命令匹配字符串开头的空白区域( 8fi - &gt; 8fiii ),并且由于结果不是 null thisIndex 被设置为上一次成功匹配的 lastIndex ,并且匹配为零 - 长度(基本上, thisIndex = previousLastIndex ), previousLastIndex 设置为 thisIndex + 1 - 在成功进行零长度匹配后跳过当前位置

您实际上可以在replace方法中使用更简单的正则表达式,并使用回调来使用适当的替换:

var res = '-12,345,678.90'.replace(/(\D)(?!.*\D)|^-|\D/g, function($0,$1) {
   return $1 ? "." : "";
});
console.log(res);

模式详情

  • (\D)(?!.*\D) - 非数字(捕获到第1组),除了换行符和其他非数字之外没有跟随0 +字符
  • | - 或
  • ^- - 字符串开头的连字符
  • | - 或
  • \D - 非数字

请注意,在这里你甚至不必在开始时选择连字符。

答案 1 :(得分:2)

你可以重新安排你的交替模式,并在JS中使用它来使它工作:

&#13;
&#13;
var arrTest = '12,345,678.90'.match(/\D(?!.*\D)|\d+|^-?/g);
console.log(arrTest);

var test = arrTest.join('').replace(/\D/, '.');

console.log(test);

//=> 12345678.90
&#13;
&#13;
&#13;

RegEx Demo

这是Javascript和PHP(PCRE)正则表达式行为之间的区别。

在Javascript中:

'12345'.match(/^|.+/gm)
//=> ["", "2345"]

在PHP中:

preg_match_all('/^|.+/m', '12345', $m);
print_r($m);
Array
(
    [0] => Array
        (
            [0] =>
            [1] => 12345
        )
    )

因此,当您在Javascript中匹配^时,正则表达式引擎会向前移动一个位置,而在交替|之后的任何内容都会从输入中的第二个位置开始匹配。