2

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

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

我怎样才能做到这一点?

4

5 回答 5

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

于 2013-01-30T22:32:45.060 回答
1

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

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

不过,我认为应该有某种方法可以使用您的正则表达式来完成这项工作。

于 2013-01-30T22:13:24.757 回答
1

您可以从 match 命令返回“匹配”对象(除非您使用过滤器将其隐式转换为字符串),唉。没有像样的文档可通过。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)
于 2013-01-30T22:23:08.090 回答
1
print '\n'.join([m.group(1) for l in lines for m in [rgx.search(l)] if m])
于 2013-01-30T22:25:34.820 回答
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'],除非您知道如何过滤掉无关数据,否则这并不是那么有趣,这些数据如此令人困惑、容易出错和脆弱 - 满分 1 星。这将是简单的,并且可能是不错的干净解决方案,涉及迭代行而不是将整个字节流摄取到内存中,但让我们坚持假设我们必须出于某种原因。也许它不是来自文件(从 TCPIP 流或其他任何东西中捕获。使用另一个单行,lines.split('\n')我们再次分隔行(没有换行符),并且可以迭代并进行理解等,但我们也可以直接跳到它使用finditer

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

相当健壮。除非您正在处理大量噩梦文件,否则我什至不确定预编译是否会更快。

于 2020-06-05T21:44:27.423 回答