python 正则表达式 - 可选匹配

-1 投票
4 回答
5121 浏览
提问于 2025-04-17 13:48

我有一堆字符串,它们的格式是这样的:

#q1_a1
#q7

基本上,#这个符号是需要忽略的。

在#后面,会跟着一个字母和一些数字。

另外,_(下划线)后面可以跟一些字母和数字的组合。

这是我想到的解决办法:

>>> pat = re.compile(r"#(.*)_?(.+)?")
>>> pat.match('#q1').groups()
('q1', None)

问题出在格式为#q1_a1的字符串上。当我把我想出来的方法应用到这样的字符串时:

>>> pat.findall('#q1_f1')
[('q1_f1', '')]

有没有什么建议呢?

4 个回答

2

你的“.*”这个表达式会把下划线也匹配上,因为它是贪婪匹配。更好的做法是写一个更具体的正则表达式,这样可以把下划线排除在第一个匹配组之外。

一个合适的正则表达式可能长这样:

#([a-z][0-9])_?([a-z][0-9])?

不过你需要检查一下,这个表达式是否适用于你所有预期的数据。

另外,正则表达式越具体越好,这样可以减少错误匹配的情况。

3

正如其他人所说,你的正则表达式越具体,就越不容易匹配到不该匹配的内容:

In [13]: re.match(r'#([A-Za-z][0-9])(?:_([A-Za-z][0-9]))?', '#q1_a1').groups()
Out[13]: ('q1', 'a1')

In [14]: re.match(r'#([A-Za-z][0-9])(?:_([A-Za-z][0-9]))?', '#q1').groups()
Out[14]: ('q1', None)

注意事项:

  1. 如果你只想匹配整个字符串,可以在正则表达式的前面加上 ^,在后面加上 $
  2. 你提到“某个数字”,但你的例子只包含一个数字。如果你的正则表达式需要接受多个数字,可以把 [0-9] 改成 [0-9]+
1

当你使用 .* 时,它会尽可能多地匹配内容,这种匹配方式叫做 贪婪匹配。你可以试试:

>>> pat = re.compile(r"#([^_]*)_?(.+)?")
>>> pat.findall('#q1_f1')
[('q1', 'f1')]

另外,写一个更具体的表达式会更好:

#([a-z][0-9])(?:_([a-z][0-9]))?

撰写回答