我的正则表达式匹配了太多内容,我该如何停止它?

120

我有一个巨大而丑陋的字符串:

J0000000: Transaction A0001401 started on 8/22/2008 9:49:29 AM
J0000010: Project name: E:\foo.pf
J0000011: Job name: MBiek Direct Mail Test
J0000020: Document 1 - Completed successfully

我正在尝试使用正则表达式从中提取片段。在这种情况下,我想抓取Project Name之后的所有内容,直到它说J0000011:(11每次都是不同的数字)。

这是我一直在尝试的正则表达式:

Project name:\s+(.*)\s+J[0-9]{7}:

问题在于它一直匹配到结尾的J0000020:才停止。

我该如何使正则表达式在第一次出现J[0-9]{7}时停止匹配?


项目名称:[^\n]*\n(J[0-9]{7}) - Aphton
5个回答

180
使 .* 非贪婪,只需在其后添加 '?' 即可:
Project name:\s+(.*?)\s+J[0-9]{7}:

15

在这里使用非贪婪量词可能是最好的解决方案,而且比贪婪匹配更有效率:贪婪匹配通常会尽可能地匹配(在这里一直到文本末尾!),然后逐个字符地回溯以尝试匹配接下来的部分。

但是,考虑使用负字符类:

Project name:\s+(\S*)\s+J[0-9]{7}:

\S表示“除空格以外的所有字符”,这正是你想要的。


当可以实现时,贪婪的负(或正)字符类通常比懒惰量词表现更好。懒惰需要引擎逐个字符地向前跟踪,每次检查后面的模式直到匹配;而贪婪的字符类可以毫不费力地重复所需的字符,这可能会更快。因此,您可能会考虑更强烈地支持负字符类,因为这是贪婪与懒惰的典型对比。 - CertainPerformance

7

".*"是一种贪婪选择器。你可以使用".*?"使其变为非贪婪选择器。当使用后者的构造时,正则表达式引擎将在每一步匹配文本到"."时尝试匹配".*?"后面可能出现的任何内容。这意味着,如果例如".*?"后面什么也没有,那么它将不会匹配任何内容。

以下是我使用的代码。变量s包含您的原始字符串。这段代码是特定于.NET的,但大多数正则表达式的风格都会有类似的东西。

string m = Regex.Match(s, @"Project name: (?<name>.*?) J\d+").Groups["name"].Value;

1

我也建议您使用“Expresso”尝试正则表达式 - 它是一个非常好用(而且免费)的正则表达式编辑和测试工具。

它的优点之一是,其用户界面公开了许多正则表达式功能,这些功能可能不为正则表达式经验不足的人所熟悉,以一种易于学习这些新概念的方式呈现。

例如,在使用UI构建正则表达式并选择“*”时,您可以选择选中“尽可能少”复选框,查看生成的正则表达式,并测试其行为,即使您以前不熟悉非贪婪表达式。

可在其网站上下载: http://www.ultrapico.com/Expresso.htm

Express下载: http://www.ultrapico.com/ExpressoDownload.htm


0
(Project name:\s+[A-Z]:(?:\w+)+.[a-zA-Z]+\s+J[0-9]{7})(?=:)

这对你很有用。

添加 (?:\w+)+.[a-zA-Z]+.* 更严格。


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