在.NET中使用重复字符和长度的正则表达式

3

我有一个正则表达式需要捕获字母部分。这些字母可以是1-3个字符的长度,但必须是相同的字母。不支持ABC,但支持A、AA或AAA,后面跟着一个数字。目前我只能匹配A1,无法匹配AA1。我正在使用.NET进行正则表达式匹配。

^(?<pool>([A-Z])\1{0,2})(?<number>(100)|[1-9]\d?)$

A1
AA2
AAA3
B5
CC7

2
你能告诉我你正在使用的编程语言吗? - Allan
喜欢这样的吗?(链接为 https://regex101.com/r/C5rLiv/2) - Gurmanjot Singh
希望我来得不算太晚。:) - wp78de 1小时前 - wp78de
2个回答

5
以下正则表达式对您是否有效?
\b(([A-Z])\2{0,2}(?:100|[1-9]\d?))\b

演示

它接受:A1 AA2 AAA3 B5 CC7,但不匹配AAAA4ABC123

如果您想使用命名捕获组和对它们的反向引用,则可以将您的正则表达式更改为:

^(?<pool>([A-Z]))\k<pool>{0,2}(?<number>(100|[1-9]\d?))$

演示,如果你觉得可以的话,请告诉我,还可以看看:

https://www.regular-expressions.info/named.html

最后但并非不重要的是,如果您想让命名捕获组<pool>匹配并捕获AAAAAA,您可以使用:

^(?<pool>([A-Z])\2{0,2})(?<number>(100|[1-9]\d?))$

演示

仅使用命名捕获组:

^(?<pool>(?<letter>[A-Z])\k<letter>{0,2})(?<number>(100|[1-9]\d?))$

演示


AA 不匹配 <pool>,只有 A。 - Mike Flynn
@MikeFlynn:让我为您修复这个。 - Allan
@MikeFlynn:最新的正则表达式怎么样? - Allan
@Allan 很好。然而,第三个模式需要使用\1作为反向引用。请参考我的回答。 - wp78de
这个答案在在线测试器上可以工作,但在.NET上却不行。有什么线索吗? - Mike Flynn

2
一个对Allan简洁答案的小补充和更正:
在.NET的正则表达式引擎中,第三个模式无法正确匹配,因为反向引用`\2`必须与所示PCRE模式(使用regex101)中的编号不同。
需要使用`\1`代替`\2`:
^(?<pool>([A-Z])\1{0,2})(?<number>(100|[1-9]\d?))$

这个dotnetfiddle演示了问题:生成了大约300个测试用例,但只有前100个(从A1到A100)匹配成功。
你可以使用regexstorm进行检查,它是一个.NET正则表达式测试工具。
为什么?在.NET正则表达式和PCRE(如PHP)中,命名捕获组与常规捕获组的引用方式存在微妙差异。
乍一看,它们的工作方式相同:

使用括号捕获的内容将自动从左到右编号,基于正则表达式中开放括号的顺序,从1开始。编号为零的捕获是整个正则表达式模式匹配的文本。

参考MSDN:正则表达式中的分组构造 因此,虽然
大多数口味的正则表达式都通过从左到右计算其开放括号的数量来对命名和未命名捕获组进行编号。将命名捕获组添加到现有的正则表达式中仍然会破坏未命名组的编号。
然而,在.NET中,未命名的捕获组首先被分配编号,从左到右计算其开放括号的数量,跳过所有命名组。之后,通过从左到右计算命名组的开放括号来分配其后面的编号。
这实际上在同一页面上解释了regular-expressions.info/named.html链接中的答案。
一个简单的例子:
要在.NET中匹配1a1,可以使用
(?<named>(\d)a)\1

在 PHP 中以类似的方式匹配,你需要使用 \2。
(?<named>(\d)a)\2

道理是:
混合使用已命名和已编号的捕获组并不推荐,因为各种正则表达式引擎在如何为这些组编码方面存在差异。
顺便说一下:
我准备了这个模式\b(?<pool>([A-Z])\1{0,2})(?<number>(\d{1,2}(?!\d)|100))\b,但后来注意到上述差异。您还可以在链接的演示中尝试使用\1\2

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