这个正则表达式中的"?"操作符是如何工作的?

4

^.*(?=.*[0-9]).*$

我看到这个正则表达式在某个人的代码中。这是一个有效的正则表达式吗?我知道?通常会使它前面的项变成可选的,比如abc?可以让c变成可选项。但是这里的?出现在一个捕获括号的开头位置。那这代表什么意思呢?


我认为php.net上PCRE文档(http://www.php.net/manual/en/reference.pcre.pattern.syntax.php)是一个很好的参考,可以教授正则表达式中许多可用功能。它涵盖了前瞻、后顾等内容... 正则表达式中的?有许多不同的用途! - Eli Sand
哦,我明白了,这些是针对PHP的吗?还是通用的正则表达式语法? - Jonas
它们是通用的。某些正则表达式的实现可能不支持所有功能,但语法相当标准。主要区别在于是否实现了POSIX或PCRE正则表达式。POSIX通常在*nix命令行/ shell系统中使用,而PCRE来自Perl,具有更多功能并且更常用。 - Eli Sand
基本上你的正则表达式意思是:1)任何东西 - 然后任何东西或数字 - 然后任何东西。2)任何东西 - 然后任何东西或数字或等号 - 然后任何东西。3)任何东西 - 只有在(任何东西或数字)跟随其后时 - 然后跟着任何东西。它们对我来说听起来都差不多,是吧? - Dr.Kameleon
我没有特别的东西要与这个正则表达式一起使用。我只是看到它感到困惑,所以我正在尝试弄清楚它的作用。我在Notepad++中进行测试...似乎不支持?= - Jonas
显示剩余4条评论
1个回答

8
? 表示:可选地匹配前面的内容。
然而,(? .. ) 用于断言...
在您的情况下,(?= 是一个先行断言,意思是:仅当括号中的内容跟在后面时才进行匹配。
参考:

(?: ... )

非捕获括号。组合所包含的模式,但不提供匹配文本的捕获。比捕获括号更有效率。

(?> ... )

原子匹配括号。首次匹配括号内的子表达式,如果没有导致整个模式匹配,则将搜索回退到“(?>”之前的位置。

(?# ... )

自由格式注释(?# comment )。

(?= ... )

先行断言。如果圆括号中的模式在当前输入位置匹配,则为True,但不会推进输入位置。

(?! ... )

负先行断言。True如果括号中的模式不匹配当前输入位置。不会推进输入位置。

(?<= ... )

后行断言。True如果括号中的模式匹配当前输入位置之前的文本,并且匹配的最后一个字符是当前位置之前的输入字符。不会更改输入位置。后向模式匹配的可能字符串长度不能无限制(没有 * 或 + 运算符)。

(?<! ... )

负后行断言。 True如果括号中的模式不匹配当前输入位置之前的文本,并且匹配的最后一个字符是当前位置之前的输入字符。不会更改输入位置。后向模式匹配的可能字符串长度不能无限制(没有 * 或 + 运算符)。


@EliSand 嗯,这也是一个相当不错的资源...很高兴你指出来了!;-) - Dr.Kameleon
抱歉,我将我的评论移动到海报上,因为那里比这里更有意义。除了断言之外,我最喜欢 ? 的好处是能够像 .*? 这样切换贪婪模式。 - Eli Sand
@Jonas嗯,没错,它不会寻找=符号。如果是像=?这样的情况,它就会寻找。所以,它确实是一个操作符。 - Dr.Kameleon
1
@Jonas - 断言基本上确保你要查找的内容存在(在前面或后面),但它不会“消耗”匹配,这意味着当正则表达式解析器移动到模式的下一部分时,它会从它命中断言时的位置继续搜索。当你掌握了它,断言是非常强大的。 - Eli Sand
@Jonas 是的,就是这样。基本上,我们告诉它匹配所有的“foo”,只要它们后面跟着(前瞻断言)一个...“foo”。所以,在我们的例子中,猜猜看:是的,它匹配除了最后一个“foo”之外的所有内容(因为它根本没有后面跟着一个“foo”)。通过使用负向前瞻断言(更常用),你也可以得到只有最后一个“foo”的结果。 (通过使用 foo(?!foo) = 匹配一个“foo”,但后面不跟着一个“foo”) - Dr.Kameleon
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接