我有一个像'234 3452789 23 901234 ...'
这样的字符串。我想提取所有数字。我写了以下正则表达式:
s = '234 3452789 23 901234'
expr = r'^\s*(\d+\s*)+$'
e = re.match(expr, s)
print e.groups()
我希望看到包含所有数字的元组,但实际上这段代码仅打印最新的数字:
('901234',)
问题:我的代码有什么问题,以及如何修复它?
P.S。以下代码效果很好,但我想用任意数量的子字符串解析字符串
expr = r'^\s*(\d+\s*)(\d+\s*)(\d+\s*)(\d+\s*)$'
e = re.match(expr, s)
print e.groups()
答案 0 :(得分:1)
TL; DR:使用findall()
:
>>> s = '234 3452789 23 901234'
>>> re.findall('\d+', s)
['234', '3452789', '23', '901234']
我希望看到包含所有数字的元组,但实际上这段代码仅打印最新的数字:
('901234',)
问题:我的代码有什么问题,以及如何修复它?
这就是match()
的工作原理,你无法做任何事情。包含一个组(如您的)的正则表达式只返回一个组。在组右侧指定+
或*
是 方式,仅获取最后一场比赛。它以设计的方式工作。
如果您真的想与match()
一起使用,regex第三方模块会提供您想要的captures
和capturesdict
方法。但它不是标准库的一部分。
答案 1 :(得分:1)
我简单的两分钱,回答你的实际问题......为什么要使用正则表达式,为什么不使用
[int(grp) for grp in s.split() if grp.isdigit()]
这会根据空格分隔符将字符串拆分为组,遍历已分隔的组列表,检查它是否为数字,如果是,则将该组推送到列表中。检查是为了确保我们只推回数字。
它(a)更快
python -m timeit -s "import re" "[int(grp) for grp in re.findall('\d+','234 3452789 23 901234')]"
>> 100000 loops, best of 3: 4.14 usec per loop
python -m timeit "[int(grp) for grp in '234 3452789 23 901234'.split() if grp.isdigit()]"
>> 100000 loops, best of 3: 2.99 usec per loop
和(b)基于我从多个讨论中读到的内容......可预测且易于理解。我曾尝试解释re.findall
,re.search
,re.split
,re.finditer
之间的细微差别。花了我一些时间。如果可以,我的建议尽量避免使用re
。
答案 2 :(得分:0)
您的第一个代码出了什么问题?
r'^\s*(\d+\s*)+$'
正则表达式应匹配起始处的所有数字或空格字符,并且仅捕获最后一位数字符和后面的零个或多个空格,因为您重复捕获组一次或多次。
例如,'(1+)'
和(1)+
正在进行相同的匹配,但两者都会捕获不同的1组。第一个正则表达式捕获所有匹配的1,其中第二个正则表达式仅捕获每个匹配中存在的最后1个。
matchobj.groups()
将返回由每个组捕获的所有字符的元组。
答案 3 :(得分:0)
它匹配^...$
引起的整个字符串,仅捕获(...)
的最后一个匹配项。我认为它不是一个足够强大的用例,尽管有人提交了issue关于允许多个匹配在列表中累积的内容。
groups()
的索引是基于正则表达式中捕获组的布局,而不是它所使用的字符串,因此无论如何都不会为每个不同的事件获取一个组。
答案 4 :(得分:-1)
结尾的$会让它选择最后一部分