如何创建一个正则表达式,不允许社会保险号中出现相同的 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 位数字,其中所有 9 位数字都相同(没有破折号):“^(\d)\1{8}$”。此表达式按预期工作(如此处所示:(https://regex101.com/r/Ez8YC3/1)).
- 第二个表达式也应该这样做,破折号的格式如下 xxx-xx-xxxx: "^(\d)\1{8}$"。此表达式按预期工作(如此处所示:https://regex101.com/r/bodzIX/1)。
此时我想做的是将它们组合在一起以寻找这两个条件。但是,当我这样做时,它似乎中断了,并且只匹配 9 个数字,这些数字在整个 WITH 破折号中都是相同的: "^(\d)\1{2}-(\d)\1{1}-(\d)\ 1{3}$|^(\d)\1{8}$"。这可以在这里看到:https://regex101.com/r/lPnksf/1.
我可能有点超前了,但为了尽可能多地展示我的工作,我也尝试分别翻转这些正则表达式,但也没有达到预期效果。
- 条件 #1 翻转:“^(?!(\d)\1{8})$”。可以在这里看到:https://regex101.com/r/ed51yk/1.
- 条件 #2 翻转:“^(?!(\d)\1{2}-(\d)\1{1}-(\d)\1{3})$”。可以在这里看到:https://regex101.com/r/UYfoMK/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})$
通过这个正则表达式,你只匹配你想要的:
^(?!(?:(\d){8})|(?:(\d){2}-{2}-{4})).*$
你要做的不是翻转,而是反转正则表达式逻辑。
是的,要反转模式逻辑,您应该使用负前瞻,但有一些注意事项。
首先,字符串锚点的 $
末尾:如果它位于“正”正则表达式的末尾,则还必须将其移至反向模式中的先行。因此,您的 ^(?!(\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}$
由于前瞻是非消耗模式,即正则表达式索引在匹配其之前的模式序列后保持在相同位置,因此 3 前瞻将全部在字符串的开头尝试(参见 ^
锚)。如果开头的三个否定前瞻中的任何一个失败,则整个字符串匹配将立即失败。
我尝试做的第一件事是让正则表达式匹配我不想要的内容。这样,我可以将其翻转为不接受相同的输入。这是我想出这个正则表达式的第一部分的地方。
- 接受所有 9 位数字,其中所有 9 位数字都相同(没有破折号):“^(\d)\1{8}$”。此表达式按预期工作(如此处所示:(https://regex101.com/r/Ez8YC3/1)).
- 第二个表达式也应该这样做,破折号的格式如下 xxx-xx-xxxx: "^(\d)\1{8}$"。此表达式按预期工作(如此处所示:https://regex101.com/r/bodzIX/1)。
此时我想做的是将它们组合在一起以寻找这两个条件。但是,当我这样做时,它似乎中断了,并且只匹配 9 个数字,这些数字在整个 WITH 破折号中都是相同的: "^(\d)\1{2}-(\d)\1{1}-(\d)\ 1{3}$|^(\d)\1{8}$"。这可以在这里看到:https://regex101.com/r/lPnksf/1.
我可能有点超前了,但为了尽可能多地展示我的工作,我也尝试分别翻转这些正则表达式,但也没有达到预期效果。
- 条件 #1 翻转:“^(?!(\d)\1{8})$”。可以在这里看到:https://regex101.com/r/ed51yk/1.
- 条件 #2 翻转:“^(?!(\d)\1{2}-(\d)\1{1}-(\d)\1{3})$”。可以在这里看到:https://regex101.com/r/UYfoMK/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})$
通过这个正则表达式,你只匹配你想要的:
^(?!(?:(\d){8})|(?:(\d){2}-{2}-{4})).*$
你要做的不是翻转,而是反转正则表达式逻辑。
是的,要反转模式逻辑,您应该使用负前瞻,但有一些注意事项。
首先,字符串锚点的 $
末尾:如果它位于“正”正则表达式的末尾,则还必须将其移至反向模式中的先行。因此,您的 ^(?!(\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}$
由于前瞻是非消耗模式,即正则表达式索引在匹配其之前的模式序列后保持在相同位置,因此 3 前瞻将全部在字符串的开头尝试(参见 ^
锚)。如果开头的三个否定前瞻中的任何一个失败,则整个字符串匹配将立即失败。