懒惰组匹配正则表达式

时间:2015-04-20 23:45:53

标签: javascript regex

我正在尝试在JavaScript中懒惰匹配一个组,但是我没有像我期望的那样工作。

"/1000/2000/".match("(?:/)(.*?)(?:/)$")

这就是我所拥有的以及我相信这个正则表达式将会做的事情:

  • 组匹配(并忽略)/字符
  • 组匹配两个/个字符之间的任何内容,但最短匹配
  • 组匹配(并忽略)/字符
  • 匹配字符串的结尾

那应该返回2000,但它会返回1000/2000。那是为什么?

4 个答案:

答案 0 :(得分:2)

(?:)是一个非捕获组 - 它仍然包含匹配中的内容,但不会为()括号创建组匹配。

分解正则表达式:

  1. (?:/)将匹配字符串中的第一个斜杠(但括号不会创建组。)
  2. (.*?)将匹配任何字符的零或多个,直到模式后续部分的第一个匹配(并且括号创建单独的捕获组)
  3. (?:/)$将匹配斜杠,紧跟字符串结尾(并且括号不会创建组)。
  4. 因此第一部分将匹配第一个字符,最后一部分将匹配最后一个字符,中间位将匹配其他匹配所需的数量(即中间的所有内容)。

    作为替代方案,这将匹配两个斜杠之间的最后一个字符串,其中最后一个斜杠位于单词的末尾:

    "/1000/2000/".match("[^/]*(?=/$)")
    

答案 1 :(得分:2)

将字符串与正则表达式匹配时,引擎会从左到右尝试每个位置,直到找到匹配项。

由于字符串是从左向右扫描的,(?:/)(.*?)(?:/)$可以在输入字符串/1000/2000/的索引0处找到匹配项。

延迟量词仅影响重复尝试的顺序。它将尝试空字符串,然后重复一次,两次,3次等。由于.匹配除行终止符之外的任何内容,并且从左到右尝试字符串,所以匹配整个/1000/2000/

顺便说一下,虽然它通常说.*?匹配可能的字符数最少,但正确的定义是 lazy量词会尝试扩展 atom (在这种情况下是.)可能的次数最少,因此续集(在本例中为(?:/)$)可以匹配。 < / p>

如其他答案中所述,解决方案是通过将/替换为.来限制[^/]之间的允许字符集。更改字符类后,您可以使用贪婪或惰性量词,因为语法已变得明确,因此搜索顺序不会影响最终结果。

答案 2 :(得分:1)

?:X模式是JavaScript中的match but do not capture指令,因此我们看到以下模式:

(?:/)(.*?)(?:/)$

转换为:

  1. (?:/)匹配/(某处),但不捕获
  2. (。*?)匹配与模式的其余部分允许的字符数
  3. (?:/)$ match / 后跟字符串结束,但不捕获
  4. 因此,第一个/被匹配并且提示被遗忘,然后我们匹配set(2),它为(?:/)$后跟的“任何字符”尝试非贪婪匹配。由于最后一部分仅匹配输入字符串末尾的斜杠,因此我们找到并忽略第一个和最后一个/,这会留下1000/2000

    如果您想要1000,那么根本没有理由打扰regexp:

    // get some input
    var s = "/1000/2000/";
    
    // split on slashes
    var t = s.split('/');
    
    // filter out empties
    t = t.filter(function(a) { return !!a ; });
    
    // convert to ints, because why not. Note that even regexp will
    // yield strings, so you still have to do this if you do use regexp.
    t = t.mapfunction(a) { return parseInt(a,10); });
    
    // results are....
    console.log(t.join(", ")); // => "1000, 2000"
    

    如果您正在寻找“斜杠之间的东西”,只需寻找不是斜线的东西:

    "/1000/2000/".match(/([^\/]+)/g) // => Array [ "1000", "2000" ]
    

答案 3 :(得分:0)

试试这个,但它并不是最优雅的解决方案:

'/1000/2000/'.match(/(?!\/)\d+(?=\/$)/);