我正在验证一个带有正则表达式、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 部分(可能(匹配时,捕获捕获组中的 C。然后,在可能的 C 部分的第二个位置,在匹配第一个捕获组之前对其进行负展望:
^M[01](?: *(C)[1-5])? *(?:(?[A-Z]{3})?(?: *(?!1)C[1-5])?)?$
^^^ ^^^^^
https://regex101.com/r/xCxSn4/1
注意,如果要匹配纯空格,可以在模式中只使用纯空格,不需要字符集:例如([ ])
等效于( )
。
使用pcre,另一种选择是使用条件来检查是否存在具有该形式的组 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(
捕获组 1h*C[1-5]
匹配 0+ 水平空格字符和数字 1-5 的 C
)?
关闭组 1 并将其设置为可选(?:
非捕获组h*([A-Z]{3})
匹配0+水平空格字符和A-Z之间的3次
)?
关闭组并将其设置为可选(?
If 子句(1)
测试捕获组 1 是否存在。如果是这样,则什么都不做|
或(?:h*C[1-5])?
可选匹配 0+ 水平空格字符和 C 与数字 1-5
)
关闭如果子句$
字符串结尾
正则表达式演示
请注意,在您尝试的模式中,匹配左括号和右括号是可选的)?
也可能匹配M1 (OSS)
。不确定这是否是预期的匹配,但我省略了那部分。