我最近一直在研究正则表达式,发现?
运算符使*
、+
或?
变得懒惰。我的问题是它是如何做到这一点的?例如,*?
是特殊运算符,还是?
对*
产生影响?换句话说,正则表达式是否将*?
本身识别为一个运算符,或者正则表达式是否将*?
识别为两个单独的运算符*
和?
?如果*?
被识别为两个独立的运算符,则?
如何影响*
以使其惰性。如果?
意味着*
是可选的,这难道不应该意味着*
根本不需要存在吗?如果是这样,那么在语句中.*?
正则表达式不会只匹配单独的字母和整个字符串而不是较短的字符串吗?请解释一下,我很想理解。非常感谢。
?
在不同的上下文中可能意味着很多不同的东西。
- 在正常的正则表达式标记(字符,速记,字符类,组...(之后,它表示"匹配前一项0-1次"。
- 在像
?
、*
、+
、{n,m}
这样的量词之后,它有不同的含义:"使前面的量词变得懒惰而不是贪婪(如果这是默认值;不过,这是可以改变的 - 例如在 PHP 中,默认情况下,/U
修饰符使所有量词变得懒惰,因此额外的?
使它们变得贪婪(。 紧跟在左括号之后,它标志着一个特殊结构的开始,例如
a(
(?s)
:模式修饰符("打开点亮模式"(
b((?:...)
:使组不捕获
c((?=...)
或(?!...)
:前瞻断言
d((?<=...)
或(?<!...)
:回溯断言
e((?>...)
: 原子群
f((?<foo>...)
:命名捕获组
g((?#comment)
:内联注释,被正则表达式引擎
忽略h((?(?=if)then|else)
:条件语句
等。并非所有构造在所有正则表达式风格中都可用。
- 在字符类(
[?]
(中,它只是匹配逐字?
。
一点历史会更容易理解。 当 Larry Wall 想要发展正则表达式语法以支持新功能时,他的选择受到严重限制。 例如,他不能只是命令%
现在是一个支持新功能"XYZ"的元字符。 这将打破数百万个现有的正则表达式,这些正则表达式恰好使用%
来匹配文字百分号。
他能做的是采用一个已经定义的元字符,并以使其原始功能没有意义的方式使用它。 例如,任何连续包含两个量词的正则表达式都是无效的,因此可以肯定地说,一个接一个量词的?
现在将其变成一个不情愿的量词(一个比"懒惰"IMO 好得多的名字;非贪婪的好也(。 所以你的问题的答案是?
不修改*
,*?
是一个单一的实体:一个不情愿的量词。 所有格量词(*+
、{0,2}+
等(中的+
也是如此。
组语法也发生了类似的过程。 在未转义的左括号之后有一个量词是没有意义的,所以可以肯定地说(?
现在标志着一个特殊组结构的开始。 但是问号本身只能支持一个新功能,所以要遵循的?
本身必须至少再跟一个字符,以表明它是哪种组((?:...)
、(?<!...)
等(。 同样,(?:
是单个实体:非捕获组的开始分隔符。
我不知道他为什么两次都用问号。 我确实知道Perl 6规则(Perl 5正则表达式的自下而上的重写(已经消除了所有这些废话,并使用了无限合理的语法。
假设您有以下文本:
BAAAAAAAAD
将返回以下正则表达式:
/B(A+)/ => 'BAAAAAAAA'
/B(A+?)/ => 'BA'
/B(A*)/ => 'BAAAAAAAA'
/B(A*?)/ => 'B'
在 + 和 * 运算符中添加 "?" 使它们"惰性"——即它们将匹配表达式为 true 所需的绝对最小值。而默认情况下,* 和 + 运算符是"贪婪的",并尝试尽可能多地匹配表达式以使表达式为真。
请记住+表示"一个或多个",因此最小值将是"如果可能的话,一个,如果绝对必要的话更多",而最大值将是"如果可能的话,一个如果绝对必要的话
"。*表示"零或更多",因此最小值将是"如果可能的话什么都没有,如果绝对必要的话更多",而最大值将是"如果可能的话,全部,如果绝对必要,则为零"。
我想这在很大程度上取决于实现。但是由于我所知道的每个量词都可以用?
进行修改,因此以这种方式实现它是合理的。