如何创建一个正则表达式,不允许社会保险号中出现相同的 9 个重复数字(带或不带连字符)?

How do I create a regex expression that does not allow the same 9 duplicate numbers in a social security number, with or without hyphens?

我尝试做的第一件事是让正则表达式匹配我不想要的内容。这样,我可以将其翻转为不接受相同的输入。这是我想出这个正则表达式的第一部分的地方。

此时我想做的是将它们组合在一起以寻找这两个条件。但是,当我这样做时,它似乎中断了,并且只匹配 9 个数字,这些数字在整个 WITH 破折号中都是相同的: "^(\d)\1{2}-(\d)\1{1}-(\d)\ 1{3}$|^(\d)\1{8}$"。这可以在这里看到:https://regex101.com/r/lPnksf/1.

我可能有点超前了,但为了尽可能多地展示我的工作,我也尝试分别翻转这些正则表达式,但也没有达到预期效果。

我希望这两个表达式(翻转时)匹配任何 9 位数字(带或不带破折号),其中所有数字都不相同。怎么这根本就没有发生。

这是我想出的最后一个正则表达式,它显然没有达到我的预期:“^(?!(\d)\1{2}-(\d)\1{ 1}-(\d)\1{3})$|^(?!(\d)\1{8})$"。可以在这里看到:https://regex101.com/r/9eHhF5/1

归根结底,我想将这两个表达式与这个表达式(已经按预期工作)结合起来:"^(?!000|666|9\d\d)\d{3 }-(?!00)\d\d-(?!0000)\d\d\d\d$"。可以在这里看到:https://regex101.com/r/AdRI8i/1.

我对正则表达式还是很陌生,真的很想知道为什么我不能简单地将条件包装在 (?!...) 中以匹配相反的条件。

提前致谢

通过这个正则表达式,你可以匹配你不想要的社会安全号码:

^(?:(\d){8})|(?:(\d){2}-{2}-{4})$

Demo

通过这个正则表达式,你只匹配你想要的:

^(?!(?:(\d){8})|(?:(\d){2}-{2}-{4})).*$

Demo

你要做的不是翻转,而是反转正则表达式逻辑。

是的,要反转模式逻辑,您应该使用负前瞻,但有一些注意事项。

首先,字符串锚点的 $ 末尾:如果它位于“正”正则表达式的末尾,则还必须将其移至反向模式中的先行。因此,您的 ^(?!(\d){8})$ 正则表达式必须写成 ^(?!(\d){8}$)。你的第二个正则表达式也是如此。

接下来,请注意每个后续捕获组都会获得一个递增的 ID 号,因此当您使用 OR | 运算符“加入”模式时,您不能保持相同的 backreferences .您必须调整这些 ID 以在新的正则表达式中反映它们的新值。

所以,你想先匹配一个匹配^(?!000|666|9\d\d)\d{3}-(?!00)\d\d-(?!0000)\d\d\d\d$的字符串(注意\d\d\d\d = \d{4}),然后你可以用lookaheads添加限制:

  • (?!(\d){8}$) - 如果从当前位置立即匹配相同的 9 位数字,然后字符串结尾出现
  • ,则匹配失败
  • (?!(\d)-(\d)-(\d){3}$) -(注意 ID 递增延续)如果从当前位置开始匹配与第一个 3 位数字相同,-,相同的 2 位数字,-,相同的5位数字,然后字符串结束.

所以,按照您的逻辑,您可以使用

^(?!(\d){8}$)(?!(\d)-(\d)-(\d){3}$)(?!000|666|9\d\d)\d{3}-(?!00)\d\d-(?!0000)\d{4}$

regex demo

由于前瞻是非消耗模式,即正则表达式索引在匹配其之前的模式序列后保持在相同位置,因此 3 前瞻将全部在字符串的开头尝试(参见 ^锚)。如果开头的三个否定前瞻中的任何一个失败,则整个字符串匹配将立即失败。