我需要设计一个正则表达式来匹配由分隔符分隔的 4 个部分 (:
在本例中)。这 4 个部分必须按顺序排列,并且每个部分之间必须有分隔符,但这些部分都是可选的。
这些都应该匹配:
A
B
C
D
A:B
A:C
A:D
B:C
B:D
C:D
A:B:C
A:B:D
A:C:D
B:C:D
A:B:C:D
同时,这些不应该匹配。
A: // cannot end with delimiter
:C // cannot start with delimiter
ABC // cannot omit delimiter
A:BC // cannot omit delimiter
A::B // cannot duplicate delimiter
... // many other possible non-matches
我的问题是我不知道如何匹配分隔符。
- 我试过了
^(A)?:?(B)?$
,但它还是匹配AB
。 - 我试过了
^(A:)?(B)?$
,但它还是匹配A:
。 - 我可以手动枚举所有 15 种匹配类型,但那会很乱 (
^(A)|(B)|(C)|(D)|(A:B)|(A:C)...........$
)。在实际的正则表达式中,A
和B
等更复杂。 - 我尝试过更简洁的枚举
^((A)|((A:)?((B)|((B:)?((C)|((C:)?(D)))))))$
,但对我来说它仍然看起来一团糟。如果我找不到更好的答案,我会选择这个选项。
您可以使冒号成为可选的,但使用单词边界来要求它在字母之间:
请参阅 regex101 上的演示
或者,您可以将所有字符设为可选,并在开始时使用前瞻来验证格式:
regex101 上的另一个演示 (
\w
匹配单词字符)如果需要匹配空字符串,只需附加
|^$
到两个模式中的任何一个(regex101 demo)或将其包装到另一个^(?:
可选组)?$
中(demo)。无需做任何花哨的事情。只需匹配一个字母和一个冒号 0 到 3 次,然后匹配一个字母:
^(?:[A-D]:){0,3}[A-D]$
https://regex101.com/r/AsjmWQ/1
如果顺序很重要,您可以在模式开头使用环视来使无序匹配无效,但是如果您的实际数据包含超过 4 个可能的值,这种方法很快就会导致复杂的模式:
^(?!.*B(?=.*A))(?!.*C(?=.*[AB]))(?!.*D(?=.*[ABC]))(?:[A-D]:){0,3}[A-D]$
https://regex101.com/r/kdz9xG/1