我正在验证带有正则表达式,PCRE风格的字符串。我有一个子字符串,可以选择出现在两个可能的位置之一中-但不能同时出现在两个位置中。我该如何为此编写正则表达式?
没有子字符串的正则表达式为
M[01]([ ]*\(?[A-Z]{3}\)?)?
子字符串具有正则表达式C [0-5],可以在括号之前或之后出现,或根本不出现。它可以用空格分隔,也可以不分隔。
有效示例(为了清晰起见,都包含空格,但没有空格的相同示例也是有效的:
M1
M1 C1
M1 (OSS)
M1 C1 (OSS)
M1 (OSS) C1
无效示例:
M1 C1 (OSS) C1
我想出的最接近的是
M[01]([ ]*C[1-5]?)([ ]*\(?[A-Z]{3}\)?)?([ ]*C[1-5]?)
但是这也会接受无效的示例。因为我只有两个职位,所以我当然可以列举不同的组合,但是我不喜欢该解决方案,因为它不能很好地扩展到更多可能的职位。
[如果这很重要,那么这是一个将在更长的字符串中待验证的组,因此正则表达式将作为子例程嵌入到更大的字符串中。
一个选项是,(如果)匹配第一个C部分时,capture捕获组中的C。然后,在可能的C部分的第二个位置,在匹配它之前先对第一个捕获组进行负前瞻:
^M[01](?: *(C)[1-5])? *(?:\(?[A-Z]{3}\)?(?: *(?!\1)C[1-5])?)?$
^^^ ^^^^^
https://regex101.com/r/xCxSn4/1
[注意,如果要匹配一个普通空格,则只需在模式中使用一个普通空格,不需要字符集:例如([ ])
等效于( )
。
使用pcre,另一种选择是利用conditional检查是否存在形式为1的组。
(?(1)foo|bar)
对于示例数据,您可以将所有3个部分设为可选,其中第一部分是捕获组。如果没有捕获组1,则匹配最后一部分。
^M[01](\h*C[1-5])?(?:\h*\([A-Z]{3}\))?(?(1)|(?:\h*C[1-5])?)$
说明
^
字符串的开头M[01]
匹配M并且为0或1(
捕获组1\h*C[1-5]
匹配0+水平空白字符和C到1-5的数字])?
关闭组1并使其为可选](?:
非捕获组\h*\([A-Z]{3}\)
匹配0+水平空白字符和A-Z之间的3次之间)?
关闭组并将其设为可选(?
If子句(1)
测试捕获组1是否存在。如果有,则什么也不做|
或(?:\h*C[1-5])?
可选地将0+水平空白字符和C与数字1-5匹配)
Close if子句$
字符串结尾请注意,在您尝试的模式中,匹配左括号和右括号是可选的\)?
,也可以匹配M1 (OSS)
。不知道这是否是预期的匹配项,但我已将该部分省略。