1

我正在尝试匹配以下格式的字符串:

S->A  
S->AbCd  
S->A|b|C|d  
S->Ab|B|cde|dB 

也就是说,在最左边正好有一个大写的拉丁字母符号,后跟“->”字面量。在该文字之后正好是一个大写/非大写拉丁字母符号或此类符号的串联,这些符号后面也可以跟以“|”分隔的此类符号组 象征。
此外,我不仅想检查整个字符串是否符合这种格式,而且还能够捕获最左边的大写符号和 '->' 文字之后的所有符号组。到目前为止,我已经想出了这个正则表达式:

([A-Z]{1})->([a-zA-Z]+)(?:(?:\|)([a-zA-Z]+))*

例如,如果我针对此字符串对其进行测试:

S->Ab|B|c|d

我得到以下结果(使用 RegexBuddy 完成测试):

Match 1:    S->Ab|B|c|d
Group 1:    S
Group 2:    Ab
Group 3:    d

好消息是我的正则表达式匹配整个字符串(这是正确的)。然而问题很明显:我的正则表达式仅捕获 '->' 文字之后的第一个和最后一个符号组。为什么?根据我对正则表达式的理解,这部分表达式

(?:(?:\|)([a-zA-Z]+))*

应该匹配所有分隔符号组。我相信这与“重复捕获组与捕获重复组”一文中描述的内容有关。我试着摆弄一下我的正则表达式,但仍然没有得到令人满意的结果。有什么建议么?

4

4 回答 4

2

正则表达式中只有三对捕获括号,因此您只能取出三个组(这与“捕获重复组与重复捕获组”有关)。组的数量始终是固定的。

为了清楚起见,使用类似 Perl 的间距m//x来拆分内容:

([a-zA-Z]{1})  ->  ([a-zA-Z]+)  (?: (?:\|) ([a-zA-Z]+) )*
^-----------^      ^---------^             ^---------^

显示了三个捕获部分。其他括号是非捕获的。显然,您可以捕获整个尾随组:

    ([a-zA-Z]{1})  ->  ([a-zA-Z]+)  ( (?:\|) (?:[a-zA-Z]+) )*

但是随后您需要对尾随组进行后处理,可能需要进行split操作,以获取子字段。

于 2012-04-25T06:16:53.280 回答
1

是的,您的问题是,您正在重复一个捕获组。

(?:(?:\|)([a-zA-Z]+))*
         ^^^^^^^^^^^
          third group

你是对的,这整个部分匹配你所有的重复组,每个匹配都存储在 中$3,所以在所有匹配完成后,你只能看到这个组的最后一个匹配,d在你的例子中。

您可以像这样捕获重复的组

([a-zA-Z]{1})->([a-zA-Z]+)((?:(?:\|)[a-zA-Z]+)*)

然后你的结果看起来像这样

Match 1:    S->Ab|B|c|d
Group 1:    S
Group 2:    Ab
Group 3:    |B|c|d
于 2012-04-25T06:20:23.437 回答
1

捕获组 3 匹配所有符号([a-zA-Z]+)- 它将首先匹配“B”,然后随着正则表达式在下一个之后的进行,它被替换为“c” |,最后它被替换为“d”,就像你的结果一样。

于 2012-04-25T06:21:22.317 回答
1

语法(?:...)表示非捕获组。

如果你想要一个捕获组,你应该使用它(...)

尝试这个:

([a-zA-Z]{1})->([a-zA-Z]+)(\|[a-zA-Z]+)*

如果您想要单独的每个元素,您可以在分隔符上拆分。

于 2012-04-25T06:16:44.093 回答