Python没有提取预期的模式

时间:2017-07-16 20:03:25

标签: python regex match

我是RegEx的新手,我正在尝试使用re.findall执行简单匹配以提取项目列表。但是,我没有得到预期的结果。你能帮我解释为什么我也会根据下面的正则表达式模式得到这个字符串的第一部分,以及我需要修改什么来获得所需的输出?

import re
string = '''aaaa_1y345_xyz_orange_bar_1
aaaa_123a5542_xyz_orange_bar_1
bbbb_1z34512_abc_purple_bar_1'''

print(re.findall('_\w+_\w+_bar_\d+', string))

当前输出:

['_1y345_xyz_orange_bar_1', '_123a5542_xyz_orange_bar_1', '_1z34512_abc_purple_bar_1']

期望的输出:

['_xyz_orange_bar_1', '_xyz_orange_bar_1', '_abc_purple_bar_1']

5 个答案:

答案 0 :(得分:3)

\w模式匹配字母,数字 _符号。根据所使用的Python版本和选项,它可以匹配的字母和数字可以来自整个Unicode范围,也可以只是ASCII。

因此,解决问题的最佳方法是将\w替换为[^\W_]

import re
string = '''aaaa_1y345_xyz_orange_bar_1
aaaa_123a5542_xyz_orange_bar_1
bbbb_1z34512_abc_purple_bar_1'''
print(re.findall(r'_[^\W_]+_[^\W_]+_bar_[0-9]+', string))
# => ['_xyz_orange_bar_1', '_xyz_orange_bar_1', '_abc_purple_bar_1']

请参阅Python demo

<强>详情:

  • _ - 下划线
  • [^\W_]+ - 一个或多个数字或字母的字符(一个[^启动否定的字符类,\W匹配任何非字的字符,_添加以匹配_
  • 以外的任何单词字符
  • _[^\W_]+ - 与上述相同
  • _bar_ - 文字子串_bar_
  • [0-9]+ - 一个或多个ASCII数字。

请参阅regex demo

答案 1 :(得分:2)

\w的使用过于宽松。它不仅会找到字母,还会找到数字和下划线。来自docs

  

如果未指定LOCALE和UNICODE标志,则匹配任何字母数字字符和下划线;这相当于集合[a-zA-Z0-9_]。对于LOCALE,它将匹配集合[0-9_]以及为当前区域设置定义为字母数字的任何字符。如果设置了UNICODE,这将匹配字符[0-9_]以及Unicode字符属性数据库中分类为字母数字的任何字符。

而是我们要匹配的实际角色分组。

_[a-z]+_[a-z]+_bar_[0-9]+

如果您确实需要\w完全匹配而没有下划线,则可以将字符分组更改为:

 [a-zA-Z0-9]

答案 2 :(得分:2)

您的代码存在的问题是\w模式等同于以下字符集:[a-zA-Z0-9_]

我猜你需要匹配同一套但没有下划线:

import re
string = '''aaaa_1y345_xyz_orange_bar_1
aaaa_123a5542_xyz_orange_bar_1
bbbb_1z34512_abc_purple_bar_1'''

print(re.findall('_[a-zA-Z0-9]+_[a-zA-Z0-9]+_bar_\d+', string))

输出:

['_xyz_orange_bar_1', '_xyz_orange_bar_1', '_abc_purple_bar_1']

答案 3 :(得分:2)

_[a-z]+_\w+_bar_\d+应该有用。

import re
string = '''aaaa_1y345_xyz_orange_bar_1
aaaa_123a5542_xyz_orange_bar_1
bbbb_1z34512_abc_purple_bar_1'''
print(re.findall('_[a-z]+_\w+_bar_\d+', string))

O / P

['_xyz_orange_bar_1', '_xyz_orange_bar_1', '_abc_purple_bar_1']

答案 4 :(得分:2)

你的问题是正则表达式是贪婪的,并尝试尽可能匹配。有时可以通过在?(加号)符号后添加+(问号)来解决此问题。但是,在您当前的解决方案中,这是不可行的(至少以任何简单的方式 - 可能会有一些前瞻性)。但是,您可以选择另一种模式,明确禁止匹配_(下划线)字符:

import re
string = '''aaaa_1y345_xyz_orange_bar_1
aaaa_123a5542_xyz_orange_bar_1
bbbb_1z34512_abc_purple_bar_1'''

print(re.findall('_[^_\W]+_[^_\W]+_bar_\d+', string))

这将符合您的希望。 [^ ... ]构造意味着,因此不是下划线而不是不是空格