以任意顺序匹配正则表达式特定的字符数量

时间:2019-07-19 10:26:14

标签: php regex pcre

我需要匹配一系列字符串:

  • 至少包含3个数字
  • 0个或更多字母
  • 0或1 -(不多)
  • 0或1 \(不多)

这些字符可以在字符串中的任何位置。

到目前为止,我的正则表达式是:

([A-Z0-9]*[0-9]{3,}[\/]?[\-]?[0-9]*[A-Z]*)

在以下情况下,这与以下数据匹配。唯一不匹配的是第一个:

02ABU-D9435
013DFC
1123451
03323456782
ADS7124536768
03SDFA9433/0
03SDFA9433/
03SDFA9433/1
A41B03423523
O4AGFC4430

Regex matches

我认为也许我对定位过于规范。如何更新此正则表达式以匹配所有可能性?

PHP PCRE

以下内容不匹配:

01/01/2018 [multiple / or -]
AA-AA   [no numbers]

谢谢

3 个答案:

答案 0 :(得分:0)

一个选项可能是使用先行断言来声明3个数字,而不是2个反斜杠,而不是2个连字符。

(?<!\S)(?=(?:[^\d\s]*\d){3})(?!(?:[^\s-]*-){2})(?!(?:[^\s\\]*\\){2})[A-Z0-9/\\-]+(?!\S)

关于图案

  • (?<!\S)声明左侧的内容不是非空白字符
  • (?=(?:[^\d\s]*\d){3})右边的断言wat是空白字符或数字的3倍
  • (?!(?:[^\s-]*-){2})断言右边的字符不是空格字符连字符的2倍
  • (?!(?:[^\s\\]*\\){2})断言右边的字符不是2倍的反斜杠字符
  • [A-Z0-9/\\-]+匹配列出的1次以上任何时间
  • (?!\S)断言右边的内容不是非空格字符

Regex demo

答案 1 :(得分:0)

可以在字符串的开头锚定正/负前瞻来检查您的模式:

  • 至少3位数字->查找(不一定连续)3位数字
  • 不超过1个'-'->断言(不一定是连续的)2个'-'字符
  • 不超过1个'/'->断言(不一定是连续的)2个'/'字符
  • 0个或更多字母->无需检查。

如果满足这些条件,则允许任何内容。

实现此的正则表达式:

^(?=(([^0-9\r\n]*\d){3}))(?!(.*-){2})(?!(.*\/){2}).*$

签出this Regex101 demo

备注

此解决方案假定每个测试的字符串都位于其自己的行上,即。不只是被空格隔开。 如果字符串之间用空格分隔,请选择solution of user @TheFourthBird(与该字符串基本相同,但要满足空格分隔)

答案 2 :(得分:0)

您可以使用捕获组和反向引用将连字符和斜杠的条件测试为相同的先行条件

~\A(?!.*([-/]).*\1)(?:[A-Z/-]*\d){3,}[A-Z/-]*\z~

demo

详细信息:

~ # using the tild as pattern delimiter avoids to escape all slashes in the pattern
\A # start of the string
(?! .* ([-/]) .* \1 ) # negative lookahead:
                        #  check that there's no more than one hyphen and one slash

(?: [A-Z/-]* \d ){3,} # at least 3 digits

[A-Z/-]* # eventual other characters until the end of the string
\z # end of the string.
~

为了更好地理解(如果您不熟悉):这三个子模式从相同位置(在这种情况下为字符串的开头)开始:

\A
(?! .* ([-/]) .* \1 )
(?: [A-Z/-]* \d ){3,}

这是可能的,因为前两个是零宽度断言,它们是简单的测试并且不占用任何字符。