正则表达式中的问号

时间:2011-04-07 15:26:49

标签: regex regex-greedy

我正在阅读regular expressions reference而我在想什么?和??字符。你能用一些例子向我解释一下它们的用处吗?我不太了解他们。

谢谢

5 个答案:

答案 0 :(得分:30)

这是一个很好的问题,我花了一段时间才看到懒惰??量词的意义。

? - 可选(贪婪)量词

?的用处很容易理解。如果您想同时找到httphttps,可以使用这样的模式:

https?

此模式将匹配两个输入,因为它使s可选。

? - 可选(懒惰)量词

??更加微妙。它通常做同样的事情?。当您询问时,它不会更改真/假结果:“此输入是否满足此正则表达式?”相反,它与问题相关:“此输入的哪一部分与此正则表达式匹配哪些部分属于哪些组?“如果输入可以多种方式满足模式,则引擎将根据???决定如何对其进行分组(或**?,或++?)。

假设您有一组要验证和解析的输入。这是一个(公认的愚蠢)例子:

Input:       
http123
https456
httpsomething

Expected result:
Pass/Fail  Group 1   Group 2
Pass       http      123
Pass       https     456
Pass       http      something

您尝试了第一件事,即this

^(http)([a-z\d]+)$
Pass/Fail  Group 1   Group 2    Grouped correctly?
Pass       http      123        Yes
Pass       http      s456       No
Pass       http      something  Yes

它们全部通过,但您无法使用第二组结果,因为您只想在第2组中使用456

好的,让我们try again。假设第2组可以是字母或数字,但不是两者:

(https?)([a-z]+|\d+)
Pass/Fail  Group 1   Group 2   Grouped correctly?
Pass       http      123       Yes
Pass       https     456       Yes
Pass       https     omething  No

现在第二个输入正常,但第三个输入错误,因为默认情况下?是贪婪的(+也是如此,但?排在第一位)。在确定shttps?还是[a-z]+|\d+的一部分时,如果结果是通过任何一种方式,正则表达式引擎将始终选择剩下。所以第2组失去s,因为第1组吸了它。

要解决此问题,请制作one tiny change

(https??)([a-z]+|\d+)$
Pass/Fail  Group 1   Group 2    Grouped correctly?
Pass       http      123        Yes
Pass       https     456        Yes
Pass       http      something  Yes

基本上,这意味着:“如果必须,请匹配https,但是当第1组只是http时,看看这是否仍然存在。”引擎意识到s可以作为[a-z]+|\d+的一部分,因此它更喜欢将其放入第2组。

答案 1 :(得分:30)

???之间的主要区别在于他们的懒惰??是懒惰的,?不是。

假设您想在文本正文中搜索“car”这个词,但您不希望仅限于单一的“汽车”;你也希望与复数“汽车”相匹配。

这是一个例句:

I own three cars.

现在,如果我想匹配单词“car”并且我只想获得字符串“car”作为回报,我会像这样使用懒惰的??:< / p>

cars??

这就是说,“寻找汽车或汽车这个词;如果你找到了,请返回car而不再”。

现在,如果我想匹配相同的单词(“car”或“cars”)并且我希望得到整个匹配,我会使用非懒惰的{ {1}}喜欢这样:

?

这就是说,“寻找汽车或汽车这个词,无论你发现什么,都要回车或汽车。”

在计算机编程领域,懒惰通常意味着“仅根据需要进行评估”。所以懒惰的cars?只返回匹配所需的数量;因为“汽车”中的“s”是可选的,所以不要退货。另一方面,非惰性(有时称为 greedy )操作尽可能地进行评估,因此??返回所有匹配,包括可选的“s”。

就我个人而言,我发现自己使用?作为使其他正则表达式运算符变得懒惰的方式(比如?*运算符)比我用于简单字符选项更常见,但是YMMV。

在Code

中查看

以上是以Clojure为例的实现:

+

(re-find #"cars??" "I own three cars.") ;=> "car" (re-find #"cars?" "I own three cars.") ;=> "cars" 是一个函数,它将第一个参数作为正则表达式re-find,并返回它在第二个参数中找到的第一个匹配#"cars??"

答案 2 :(得分:11)

?只是使前一项(字符,字符类,组)可选:

colou?r

匹配“颜色”和“颜色”

(swimming )?pool

匹配“游泳池”和“游泳池”

??是相同的,但它也是懒惰的,所以如果可能的话, 项将被排除。正如那些文件所指出的那样,??在实践中很少见。我从来没有用过它。

答案 3 :(得分:8)

正则表达式中的其他一些问号

除了在其他答案中解释的内容之外,在正则表达式中还有3个问号用途。

  1. 否定前瞻

    如果您愿意,可以使用否定前瞻 匹配的东西没有其他东西。否定的 lookahead构造是一对括号,带有开口 括号后跟一个问号和一个感叹号。 x(?!x2)

    示例

    • 考虑一个单词There
    • 现在,默认情况下,RegEx e会在字e中找到第三个字母There

      There
        ^
      
    • 但是,如果您不希望e紧跟r,那么您可以使用RegEx e(?!r)。现在的结果将是:

      There
          ^
      
  2. 积极前瞻

    积极前瞻的作用是一样的。 q(?=u)q匹配 紧接着是u,而不是u部分 比赛。积极的先行构造是一对括号, 用左括号后跟一个问号和一个 等于。

    示例

    • 考虑一个单词getting
    • 现在,默认情况下,RegEx t会在字t中找到第三个字母getting

      getting
        ^
      
    • 但是,如果您希望t紧跟i,那么您可以使用RegEx t(?=i)。现在的结果将是:

      getting
         ^
      
  3. 非捕获群组

    每当你在括号()中放置正则表达式时,它们就会出现 创建一个编号的捕获组。它存储字符串的一部分 匹配的是正则表达式中的部分 括号中。

    如果您不需要该组捕获其匹配项,则可以进行优化 这个正则表达式进入

    (?:Value)
    
  4. 另请参阅thisthis

答案 4 :(得分:1)

在Oracle文档中使用“(一次或根本不)匹配” AutoMapper勉强量词运行测试工具表明,它可以保证始终为空。

X??

https://docs.oracle.com/javase/tutorial/essential/regex/quant.html

似乎与空匹配项相同。

$ java RegexTestHarness

Enter your regex: x?
Enter input string to search: xx
I found the text "x" starting at index 0 and ending at index 1.
I found the text "x" starting at index 1 and ending at index 2.
I found the text "" starting at index 2 and ending at index 2.

Enter your regex: x??
Enter input string to search: xx
I found the text "" starting at index 0 and ending at index 0.
I found the text "" starting at index 1 and ending at index 1.
I found the text "" starting at index 2 and ending at index 2.