问题 Python re.findall表现得很奇怪


源字符串是:

# Python 3.4.3
s = r'abc123d, hello 3.1415926, this is my book'

这是我的模式:

pattern = r'-?[0-9]+(\\.[0-9]*)?|-?\\.[0-9]+'

然而, re.search 可以给我正确的结果:

m = re.search(pattern, s)
print(m)  # output: <_sre.SRE_Match object; span=(3, 6), match='123'>

re.findall 只是转出一个空列表:

L = re.findall(pattern, s)
print(L)  # output: ['', '', '']

为什么不能 re.findall 给我预期的清单:

['123', '3.1415926']

8665
2017-08-10 08:33


起源

将捕获组转为非捕获组。 - Avinash Raj
@AvinashRaj,嗯..,如果我删除那个捕获组,甚至re.search给我一个无结果 - O'Skywalker
@stribizhev,它不是,'3.1415926'应该是结果中的一个浮点数 - O'Skywalker
@ O'Skywalker尝试使用puttern像 - ?\ d?\。?\ d + - Dmitry.Samborskyi


答案:


s = r'abc123d, hello 3.1415926, this is my book'
print re.findall(r'-?[0-9]+(?:\.[0-9]*)?|-?\.[0-9]+',s)

你不需要 escape 你使用时两次 raw mode

输出:['123', '3.1415926']

返回类型也将是一个列表 strings如果你想要返回类型为 integers 和 floats 使用 map

import re,ast
s = r'abc123d, hello 3.1415926, this is my book'
print map(ast.literal_eval,re.findall(r'-?[0-9]+(?:\.[0-9]*)?|-?\.[0-9]+',s))

输出: [123, 3.1415926]


5
2017-08-10 08:41



虽然这个正则表达式效率低于我的效率,但我承认这个技巧 ast 很酷(虽然OP中没有要求)。 - Wiktor Stribiżew
@stribizhev我读了他的一条评论....@stribizhev, it's not, '3.1415926' should be a float number in the result 所以我把它包含在我的答案:) - vks
你们两个都是天才,我很难选择接受哪一个。 :) - O'Skywalker
@ O'Skywalker:选择最适合你的那个。请不要明天改变主意,我们都不会高兴看到声望下降了-15分:) - Wiktor Stribiżew
@ O'Skywalker就像天才一样:P ..........只是练习.......你很快就会成为一名警察!!!!!!!! - vks


这里有两点需要注意:

  • re.findall 如果正则表达式模式中包含捕获组,则返回捕获的文本 
  • r'\\.' 你的模式中的部分匹配两个连续的字符, \ 以及换行以外的任何字符。

看到 findall 参考

如果模式中存在一个或多个组,则返回组列表;如果模式有多个组,这将是一个元组列表。结果中包含空匹配,除非它们触及另一个匹配的开头。

注意 制作 re.findall 返回只匹配值,你通常可以

  • 删除多余的捕获组(例如 (a(b)c)  - > abc
  • 将所有捕获组转换为 非捕获 (即替换 ( 同 (?:除非 有反向引用参考模式中的组值(见下文)
  • 使用 re.finditer 相反([x.group() for x in re.finditer(pattern, s)]

在你的情况下, findall 返回所有已捕获的文本,因为你有空 \\ 中 r'' 试图匹配文字的字符串文字 \

要匹配数字,您需要使用

-?\d*\.?\d+

正则表达式匹配:

  • -?  - 可选减号
  • \d*  - 可选数字
  • \.?  - 可选的小数分隔符
  • \d+  - 1位或更多位数。

看到 演示

这是 IDEONE演示

import re
s = r'abc123d, hello 3.1415926, this is my book'
pattern = r'-?\d*\.?\d+'
L = re.findall(pattern, s)
print(L)

9
2017-08-10 08:40