Quantifiers

量词允许您指定要匹配的出现次数。为方便起见,下面介绍了 PatternAPI 规范的三个部分,分别描述了贪婪,不情愿和所有格的量词。乍一看,量词X?X??X?+做的完全相同,因为它们都承诺匹配“ X,一次或根本不匹配”。存在细微的实现差异,将在本节末尾进行解释。

GreedyReluctantPossessiveMeaning
X?X??X?+X,一次或根本不
X*X*?X*+X,零次或多次
X+X+?X++X次,一次或多次
X{n}X{n}?X{n}+X,正好n
X{n,}X{n,}?X{n,}+X,至少n
X{n,m}X{n,m}?X{n,m}+X,至少n但不超过m

让我们从创建三个不同的正则表达式开始看贪婪量词:字母“ a”后跟?*+。让我们看看针对空 Importing 字符串""测试这些表达式时会发生什么:

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

Enter your regex: a*
Enter input string to search: 
I found the text "" starting at index 0 and ending at index 0.

Enter your regex: a+
Enter input string to search: 
No match found.

Zero-Length Matches

在上面的示例中,在前两种情况下匹配成功,因为表达式a?a*都允许字母a出现零次。您还将注意到,开始索引和结束索引均为零,这与到目前为止我们看到的任何示例都不相同。空的 Importing 字符串""没有 Long 度,因此测试仅在索引 0 处不匹配任何内容。此类匹配称为零 Long 度匹配。零 Long 度匹配可能在几种情况下发生:在空的 Importing 字符串 中,在 Importing 字符串 的开头,在 Importing 字符串 的最后一个字符之后或在 Importing 字符串 的任何两个字符之间。零 Long 度匹配总是容易识别,因为它们始终在相同的索引位置开始和结束。

让我们通过更多示例探讨零 Long 度匹配。将 Importing 字符串 更改为单个字母“ a”,您会发现一些有趣的事情:

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

Enter your regex: a*
Enter input string to search: a
I found the text "a" starting at index 0 and ending at index 1.
I found the text "" starting at index 1 and ending at index 1.

Enter your regex: a+
Enter input string to search: a
I found the text "a" starting at index 0 and ending at index 1.

所有三个量词都找到字母“ a”,但前两个量词还在索引 1 处找到零 Long 度匹配;也就是说,在 Importing 字符串 的最后一个字符之后。请记住,匹配器将字符“ a”视为位于索引 0 和索引 1 之间的单元中,并且我们的测试工具循环运行,直到无法找到匹配为止。根据所使用的量词,最后一个字符之后的索引处“无”可能会触发也可能不会触发匹配。

现在,将 Importing 字符串 连续五次更改为字母“ a”,您将获得以下内容:

Enter your regex: a?
Enter input string to search: aaaaa
I found the text "a" starting at index 0 and ending at index 1.
I found the text "a" starting at index 1 and ending at index 2.
I found the text "a" starting at index 2 and ending at index 3.
I found the text "a" starting at index 3 and ending at index 4.
I found the text "a" starting at index 4 and ending at index 5.
I found the text "" starting at index 5 and ending at index 5.

Enter your regex: a*
Enter input string to search: aaaaa
I found the text "aaaaa" starting at index 0 and ending at index 5.
I found the text "" starting at index 5 and ending at index 5.

Enter your regex: a+
Enter input string to search: aaaaa
I found the text "aaaaa" starting at index 0 and ending at index 5.

表达式a?为每个字符找到一个单独的匹配项,因为当“ a”出现零次或一次时,它就匹配。表达式a*找到两个单独的匹配项:第一个匹配项中的所有字母“ a”,然后在索引 5 的最后一个字符之后的零 Long 度匹配项。最后,a+匹配所有出现的字母“ a”,忽略最后一个索引中“无”的存在。

在这一点上,您可能想知道如果前两个量词遇到的字母不是“ a”,那么结果将是什么。例如,如果遇到字母“ b”,如“ ababaaaab”,会发生什么?

让我们找出:

Enter your regex: a?
Enter input string to search: ababaaaab
I found the text "a" starting at index 0 and ending at index 1.
I found the text "" starting at index 1 and ending at index 1.
I found the text "a" starting at index 2 and ending at index 3.
I found the text "" starting at index 3 and ending at index 3.
I found the text "a" starting at index 4 and ending at index 5.
I found the text "a" starting at index 5 and ending at index 6.
I found the text "a" starting at index 6 and ending at index 7.
I found the text "a" starting at index 7 and ending at index 8.
I found the text "" starting at index 8 and ending at index 8.
I found the text "" starting at index 9 and ending at index 9.

Enter your regex: a*
Enter input string to search: ababaaaab
I found the text "a" starting at index 0 and ending at index 1.
I found the text "" starting at index 1 and ending at index 1.
I found the text "a" starting at index 2 and ending at index 3.
I found the text "" starting at index 3 and ending at index 3.
I found the text "aaaa" starting at index 4 and ending at index 8.
I found the text "" starting at index 8 and ending at index 8.
I found the text "" starting at index 9 and ending at index 9.

Enter your regex: a+
Enter input string to search: ababaaaab
I found the text "a" starting at index 0 and ending at index 1.
I found the text "a" starting at index 2 and ending at index 3.
I found the text "aaaa" starting at index 4 and ending at index 8.

即使字母“ b”出现在单元格 1、3 和 8 中,输出也会在这些位置报告零 Long 度匹配。正则表达式a?不是专门寻找字母“ b”;而是它只是在寻找字母“ a”的存在(或缺乏)。如果量词允许“ a”匹配零次,则 Importing 字符串 中不是“ a”的任何内容都将显示为零 Long 度匹配。其余的 a 根据前面示例中讨论的规则进行匹配。

要完全匹配一个 Patternn 次,只需在一组花括号内指定数字即可:

Enter your regex: a{3}
Enter input string to search: aa
No match found.

Enter your regex: a{3}
Enter input string to search: aaa
I found the text "aaa" starting at index 0 and ending at index 3.

Enter your regex: a{3}
Enter input string to search: aaaa
I found the text "aaa" starting at index 0 and ending at index 3.

在这里,正则表达式a{3}正在搜索连续出现的三个字母“ a”。第一次测试失败,因为 Importing 字符串 没有足够的 a 来匹配。第二个测试在 Importing 字符串 中恰好包含 3 个 a,这会触发匹配。第三个测试也会触发匹配,因为在 Importing 字符串 的开头恰好有 3 个 a。以下与第一场 match 无关的任何事情。如果该 Pattern 在该点之后再次出现,则将触发后续匹配:

Enter your regex: a{3}
Enter input string to search: aaaaaaaaa
I found the text "aaa" starting at index 0 and ending at index 3.
I found the text "aaa" starting at index 3 and ending at index 6.
I found the text "aaa" starting at index 6 and ending at index 9.

要要求图案至少出现 n 次,请在数字后添加一个逗号:

Enter your regex: a{3,}
Enter input string to search: aaaaaaaaa
I found the text "aaaaaaaaa" starting at index 0 and ending at index 9.

使用相同的 Importing 字符串,此测试仅找到一个匹配项,因为连续的 9 个 a 满足“至少” 3 个 a 的需要。

最后,要指定出现次数的上限,请在花括号内添加第二个数字:

Enter your regex: a{3,6} // find at least 3 (but no more than 6) a's in a row
Enter input string to search: aaaaaaaaa
I found the text "aaaaaa" starting at index 0 and ending at index 6.
I found the text "aaa" starting at index 6 and ending at index 9.

在这里,第一场 match 被迫停止在 6 个字符的上限。第二个匹配项包括剩下的所有内容,恰好是三个 a-该匹配项允许的最少字符数。如果 Importing 字符串 短一个字符,则不会有第二个匹配项,因为将仅保留两个 a。

使用量词catch组和字符类

到目前为止,我们仅在包含一个字符的 Importing 字符串 上测试了量词。实际上,量词一次只能附加一个字符,因此正则表达式“ abc”表示“ a,后跟 b,再后跟 c 一次或多次”。它不会一次或多次表示“ abc”。但是,量词也可以附加到Character ClassesCapturing Groups,例如[abc]+(a 或 b 或 c,一次或多次)或(abc)+(组“ abc”,一次或多次)。

让我们通过连续三次指定组(dog)进行说明。

Enter your regex: (dog){3}
Enter input string to search: dogdogdogdogdogdog
I found the text "dogdogdog" starting at index 0 and ending at index 9.
I found the text "dogdogdog" starting at index 9 and ending at index 18.

Enter your regex: dog{3}
Enter input string to search: dogdogdogdogdogdog
No match found.

在这里,第一个示例找到三个匹配项,因为量词适用于整个catch组。但是,删除括号,并且匹配失败,因为量词{3}现在仅适用于字母“ g”。

同样,我们可以对整个字符类应用量词:

Enter your regex: [abc]{3}
Enter input string to search: abccabaaaccbbbc
I found the text "abc" starting at index 0 and ending at index 3.
I found the text "cab" starting at index 3 and ending at index 6.
I found the text "aaa" starting at index 6 and ending at index 9.
I found the text "ccb" starting at index 9 and ending at index 12.
I found the text "bbc" starting at index 12 and ending at index 15.

Enter your regex: abc{3}
Enter input string to search: abccabaaaccbbbc
No match found.

在这里,量词{3}在第一个示例中适用于整个字符类,但在第二个示例中仅适用于字母“ c”。

贪婪,勉强和所有格量词之间的差异

贪婪,勉强和所有格修饰语之间存在细微的差异。

贪婪的量词被认为是“贪婪的”,因为它们会迫使匹配器在try首次匹配之前先读取或吃掉整个 Importing 字符串。如果第一次匹配try失败(整个 Importing 字符串)失败,则匹配器将 Importing 字符串 退回一个字符,然后再次try,重复此过程,直到找到匹配项或没有其他要退回的字符。根据表达式中使用的量词,它将try与之匹配的最后一件事是 1 或 0 个字符。

但是,勉强的量词采用相反的方法:它们从 Importing 字符串 的开头开始,然后勉强地一次吃一个字符以寻找匹配项。他们try的最后一件事是整个 Importing 字符串。

最后,所有格量词总是吃掉整个 Importing 字符串,try一次(也只有一次)进行匹配。与贪婪的量词不同,所有格量词从不退缩,即使这样做会使整体匹配成功。

为了说明,请考虑 Importing 字符串xfooxxxxxxfoo

Enter your regex: .*foo  // greedy quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfooxxxxxxfoo" starting at index 0 and ending at index 13.

Enter your regex: .*?foo  // reluctant quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfoo" starting at index 0 and ending at index 4.
I found the text "xxxxxxfoo" starting at index 4 and ending at index 13.

Enter your regex: .*+foo // possessive quantifier
Enter input string to search: xfooxxxxxxfoo
No match found.

第一个示例使用贪婪的量词.*查找零次或多次“任何”,后跟字母"f" "o" "o"。因为量词是贪婪的,所以表达式的.*部分首先会吃掉整个 Importing 字符串。此时,整个表达式无法成功,因为最后三个字母("f" "o" "o")已被占用。因此,匹配器每次一次缓慢地退回一个字母,直到最右边出现的“ foo”重新反响为止,这时匹配成功并且搜索结束。

但是,第二个示例是勉强的,因此首先要先消耗“无”。因为“ foo”没有出现在字符串 的开头,所以它被迫吞下第一个字母(“ x”),这会在 0 和 4 处触发第一个匹配。我们的测试工具将 continue 该过程,直到 Importing 字符串 为累。它在 4 和 13 找到另一个匹配项。

第三个示例找不到匹配项,因为量词是所有格。在这种情况下,整个 Importing 字符串 将被.*+占用,而在表达式末尾不留任何内容来满足“ foo”。如果您想抓住所有东西而又不退缩,请使用所有格量词;如果没有立即找到匹配项,它将胜过等效的贪婪量词。