如何将正则表达式变成非贪婪模式?

289

我正在使用jQuery。我有一个包含特殊字符块(开头和结尾)的字符串。我想要获取该特殊字符块中的文本内容。我使用了正则表达式对象进行字符串查找。但是当有两个或更多特殊字符时,我该如何告诉jQuery查找多个结果?

我的HTML代码:

<div id="container">
    <div id="textcontainer">
     Cuộc chiến pháp lý giữa [|cơ thử|nghiệm|] thị trường [|test2|đây là test lần 2|] chứng khoán [|Mỹ|day la nuoc my|] và ngân hàng đầu tư quyền lực nhất Phố Wall mới chỉ bắt đầu.
    </div>
</div>

我的 JavaScript 代码:

$(document).ready(function() {
  var takedata = $("#textcontainer").text();
  var test = 'abcd adddb';
  var filterdata = takedata.match(/(\[.+\])/);

  alert(filterdata); 

  //end write js 
});

我的结果是:[|cơ thử|nghiệm|] thị trường [|test2|đây là test lần 2|] chứng khoán [|Mỹ|day la nuoc my|]。但这不是我想要的结果:(。如何获得1次的[text]和2次的[demo]?
我在互联网上搜索信息后刚刚完成了我的工作^^。我编写了以下代码:
var filterdata = takedata.match(/(\[.*?\])/g);
  • 我的结果是:[|cơ thử|试验|],[|test2|这是第二次测试|]。这是正确的!但我真的不太理解。你能回答我为什么吗?

这个回答对我很有帮助。 - kirogasa
3个回答

625
非贪心正则表达式修饰符与贪心正则表达式修饰符类似,但在它们后面立即跟着一个 ? 符号。
*  - zero or more
*? - zero or more (non-greedy)
+  - one or more
+? - one or more (non-greedy)
?  - zero or one
?? - zero or one (non-greedy)

37
需要注意的是,单独的问号 ? 表示可选,可以出现一次或零次(但是会优先匹配尽可能多的字符)。例如,'bb'.replace(/b?/, 'a') //'ab''bb'.replace(/c?/, 'a') //'abb' - Hashbrown
3
C语言中为什么会出现“match nothing there”的情况? - Muhammad Umer
4
我认为他的意思是因为 c 不会匹配,但是你有 ?,它代表的是 0 或 1,那么它将匹配 0 个 c 字符,因此替换掉了它。但我不知道它的工作原理,因为我试过的任何正则表达式引擎都无法编译它。 - Noctis
如果您仍需要支持MSIE 11,那么了解它不支持正则表达式的s标志是很重要的。我最初认为MSIE不支持非贪婪修饰符,但实际原因是我的正则表达式中有s标志。 - Mikko Rantalainen
1
???之间到底有什么区别?我不太明白贪婪和非贪婪的零或一次匹配条件之间的区别。请帮助我理解。 - Konrad Viltersten
1
@KonradViltersten 这与捕获有关。例如,'abcd'.match(/(a)?b??(.*)/) 将产生两个捕获组 abcd,因为它懒惰地匹配 b,所以 b 被包含在贪婪的 .* 匹配中。如果没有双重的 ?,它只会产生一个捕获组 acd,因为 b 在捕获开始之前被消耗掉了。 - Waddles

47

你说得对,贪婪性是一个问题:

--A--Z--A--Z--
  ^^^^^^^^^^
     A.*Z
如果你想匹配 A--Z,你需要使用 A.*?Z? 使 * 变得“勉强”,或者懒惰)。
不过有时候有更好的方法,例如:
A[^Z]*+Z

这里使用了否定字符类和占有量词,以减少回溯,并且很可能更有效率。

对于你的情况,正则表达式应该是:

/(\[[^\]]++\])/

不幸的是,JavaScript正则表达式不支持贪婪量词,所以你只能使用以下方法:

/(\[[^\]]+\])/

另请参见


快速摘要

*   Zero or more, greedy
*?  Zero or more, reluctant
*+  Zero or more, possessive

+   One or more, greedy
+?  One or more, reluctant
++  One or more, possessive

?   Zero or one, greedy
??  Zero or one, reluctant
?+  Zero or one, possessive

请注意,勉强和占有量词也适用于有限重复的{n,m}构造。

Java示例:

System.out.println("aAoZbAoZc".replaceAll("A.*Z", "!"));  // prints "a!c"
System.out.println("aAoZbAoZc".replaceAll("A.*?Z", "!")); // prints "a!b!c"

System.out.println("xxxxxx".replaceAll("x{3,5}", "Y"));  // prints "Yx"
System.out.println("xxxxxx".replaceAll("x{3,5}?", "Y")); // prints "YY"

我将你的正则表达式复制到我的工作中,结果是: 无效的量词+\]) [在此错误处中断] var filterdata = takedata.match(/(\[[^\]]++\])/);\n (firebugs + Firefox)有什么问题吗? - Rueta
@Rueta:显然JavaScript不支持贪婪匹配。我已经编辑了我的答案以反映这一事实。你可以只使用一个 + 而不是两个。 - polygenelubricants
1
尽管原子组可以用来代替占有量词,但JavaScript也不支持原子组。但是还有第三种选择,请参见此链接:http://instanceof.me/post/52245507631/regex-emulate-atomic-grouping-with-lookahead - 您可以使用LookAhead模拟原子分组。(?>a)变成(?=(a))\1 - Roland Pihlakas
6
这是一个针对JavaScript问题的Java答案,Java != JavaScript,请读者注意。 - Roshambo

3
我相信应该是这样的。
takedata.match(/(\[.+\])/g);

末尾的g代表全局匹配,因此它不会在第一个匹配处停止。


是的,在/g中你是正确的。我刚刚用你的答案完成了我的工作^^。但是当我使用正则表达式/(\[.+\])/g时,我的结果是: [|cơ thử|nghiệm|] thị trường [|test2|đây là test lần 2|] chứng khoán [|Mỹ|day la nuoc my|] :( - Rueta

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