Python从列表中获取所有正则表达式匹配组

时间:2013-01-30 22:06:52

标签: python regex

假设我已经阅读了文本文件的所有行,如下所示:

ifile = open('myfile.txt')
lines = ifile.readlines()

现在,假设我有以下正则表达式:

rgx = re.compile(r'Found ([0-9]+) solutions')

我可以用

result = filter(rgx.match,lines)
print result

获取匹配列表,但我想要的是匹配组列表。例如,而不是输出如:

Found 3 solutions
Found 35 solutions
Found 0 solutions

我希望输出如下:

3
35
0

我该怎么做?

5 个答案:

答案 0 :(得分:2)

import re

rgx = re.compile(r'Found ([0-9]+) solutions')

with open('myfile.txt') as f:
    result = [m.group(1) for m in (rgx.match(line) for line in f) if m]

内部循环(rgx.match(line) for line in f)是一个生成器表达式,其行为类似于apply()。对于文件中的每一行,它调用rgx.match()并产生结果,SRE_Match对象(我通常称之为“匹配对象”)。

外部循环有if m,它会丢弃任何不评估为true的结果(re.match()在模式不匹配时返回None)。然后m.group(1)使用匹配对象从括号内获取文本。有关详细信息,请参阅re模块的文档。由于外部循环是列表推导的一部分,因此构建并返回结果列表。

答案 1 :(得分:1)

由于前缀和后缀是固定字符串,因此您可以使用环视:

r'(?<=Found )\d+(?= solutions)'

我认为应该有一些方法可以使用你的正则表达式来完成这项工作。

答案 2 :(得分:1)

你从匹配命令返回“匹配”对象(除非你使用过滤器隐式地将它变成一个字符串),唉。没有像样的文件。 ipython帮助,但它在线:http://docs.python.org/3/library/re.html#match-objects

例如

for line in lines:
  result = rgx.match(line)
  if not result: continue
  print result.group(1)

答案 3 :(得分:1)

print '\n'.join([m.group(1) for l in lines for m in [rgx.search(l)] if m])

答案 4 :(得分:0)

因此,此处提供的其他解决方案很好,并且可能是最具可读性的,但是在您的特定需求示例中,我建议您使用几种单行方法(当然请记住,您的问题来自2013年而且您可能不在同一家公司工作,更不用说在同一项目中工作了)。我也认为,如果有人在这里找到自己,这将引起一些普遍兴趣。因为前提非常简单(每行上都有一个有趣的数据),所以您可以执行以下操作:

>>> # simulate reading the (hopefully not ginormous) file into a single string
>>> lines = "Found 3 solutions\nFound 35 solutions\nFound 0 solutions\n"
>>> # we're now in the state we would be after "lines = file.readlines()"
>>> print(lines)
Found 3 solutions
Found 35 solutions
Found 0 solutions

>>> # we're so constrained, we can get away with murder in a single line
>>> solution_counts = re.findall(r'\d+', file_contents)
>>> solution_counts
['3', '35', '0']
>>> # bazinga!

这是一个非常强大的解决方案。如果将文件本地化时将“找到的”和“解决方案”一词更改为翻译后的等效项,则只要格式保持不变,该解决方案就不会在意。不包含十进制整数的页眉和页脚?不在乎。它可以在像"Found solution sets of count 3, 35, and 0"这样的单个字符串上工作,完全相同的代码将提取您想要的答案。但是,更常见的情况是您知道格式但无法控制它,并且每行/记录都充满了异构数据,并且您关心的部分周围都是您可能会或可能不会关心的其他部分。因此,请考虑以下古怪的变体:

file_contents = "99 bottles of beer on the wall\n" \
                "50 ways to leave your lover\n" \
                "6 kinds of scary\n" \
                "Found 3 solutions of type A\n" \
                "Found 35 solutions of type C\n" \
                "Found 4 solutions of unknown type\n" \
                "2 heads are better than 1\n" \
                "etc, ...\n"

我们的幼稚解决方案将返回['99', '50', '6', '3', '35', '4', '2', '1'],除非您不知道如何过滤无关的数据,否则它就不会那么有趣,这样会造成混乱,容易出错和脆弱-五分之一星。这将很容易,并且可能是一个不错的干净解决方案,其中涉及遍历行而不是将整个字节流都提取到内存中,但是让我们坚持必须出于某种原因而做出的假设。也许它不是来自一个文件(从TCPIP流或其他任何文件捕获的。使用另一种单行lines.split('\n'),我们又将行分隔开了(没有换行符),并且可以进行迭代和理解等。 ,但我们也可以使用finditer

跳到右边
>>> [ m.group(1) for m in re.finditer(r'Found (\d+)', file_contents) ]
>>> ['3', '35', '4']

相当强大。我什至不知道预编译会更快,除非您正在处理大量噩梦文件。