使用正则表达式 Python 3 指定多个匹配“长度”

Specify Multiple Match "Lengths" with Regex Python 3

提问人:csharp1321 提问时间:10/30/2023 更新时间:10/30/2023 访问量:53

问:

我是正则表达式的新手,不知道该如何问这个问题,但我会尽力而为。

这是我正在使用的一个简单的表达式:

"^[0-9]{13}$"

这与长度正好为 13 个字符的数字字符串匹配。根据 Python 文档,我可以设置一个这样的范围,该范围将与长度在 13 到 20 个字符之间的任意数字字符串匹配,例如:

"^[0-9]{13,20}$"

我的问题是,如何从范围中排除某些“长度”?例如:

"^[0-9]{13,20 EXCEPT for 15 or 17}$"

在该示例中,我想包括 13 到 20 之间的任何长度,但 15 和 17 除外。

这可能吗?

我已经查看了 Python 3 正则表达式文档,但我个人找不到一种方法来做到这一点,但我也没有经验,所以我可能会忽略一些东西。

python-3.x 正则表达式

评论

2赞 Tim Roberts 10/30/2023
不,这是不可能的。之后只需检查比赛并拒绝长度错误的比赛即可。正则表达式已经完成了艰巨的工作。
1赞 jasonharper 10/30/2023
^(?!.{15}$)(?!.{17}$)[0-9]{13,20}$- 两个否定展望拒绝任何属于禁止长度之一的字符串。并不是说这是实现您的要求的好方法,只是说这是可能的
0赞 rioV8 10/30/2023
^[0-9]{13}([0-9]([0-9][0-9]([0-9][0-9]{1,3})?)?)?$,但 Jason 的正则表达式更具可读性

答:

0赞 InSync 10/30/2023 #1

井。。。是的,你可以,但这需要的不仅仅是一个量词。

有其他选择

^
(?:
  [0-9]{13,14}   # 13 or 14
|
  [0-9]{16}      # or 16
|
  [0-9]{18,20}   # or 18, 19, 20.
)
$

展望

^
(?!.{15}$)(?!.{17}$)    # Assure that the length is neither 15 nor 17,
[0-9]{13,20}            # and at the same time, 13 <= length <= 20.
$

使用回溯

^
[0-9]{13,20}            # Basically the same pattern,
(?<!^.{15})(?<!^.{17})  # just inverted.
$

使用普通的 Python 代码:

# Note the lack of anchors and the use of .fullmatch()
# That method is used here since it is more readable,
# and it automatically adds anchors.

_13_to_20_digits = re.compile('[0-9]{13,20}')

if _13_to_20_digits.fullmatch(text) and len(text) not in (15, 17):
  frobnicate()

选择一个。随心所欲。就我个人而言,我喜欢最后一个,因为它非常清楚,即使对于那些不知道正则表达式的人来说也是如此。[需要引证]

0赞 Timeless 10/30/2023 #2

在第二种模式中,您可以将字符串的开头替换为自定义/受限制的字符串开头(根据要排除的长度构建)。这将确保匹配字符串的每个开头,但前提是此字符串的长度不是 15 或 17 个字符。^^(?!(.{15}|.{17})$)

Use ^(?!(.{15}|.{17})$)[0-9]{13,20}$ instead of ^[0-9]{13,20}$

下面是一个通用代码来处理不同的不连续范围:

# feel free to adjust the values
(l, r), excep = [13, 20], [15, 17]

to_excl = "|".join(".{%s}" % n for n in excep)

pat = re.compile(r"^(?!(%s)$)[0-9]{%s,%s}$" % (to_excl, l, r))

测试/输出 :

for t in text:
    print(
        f"{t:<22}", f"{len(t):<4}",
        "match" if pat.match(t) else "no-match"
    )
    
01234                  5    no-match
012345678901234        15   no-match
0123456789012345       16   match
01234567890123456      17   no-match
012345678901234567     18   match
012345678901234567890  21   no-match

使用的输入:

from string import digits
s = digits; lens = [5, 15, 16, 17, 18, 21]
text = [s * (l // 10) + s[:l % 10] for l in lens]
   
['01234',
 '012345678901234',
 '0123456789012345',
 '01234567890123456',
 '012345678901234567',
 '012345678901234567890']

评论

1赞 csharp1321 10/30/2023
这太完美了!感谢您的帮助和见解!