假设我已经阅读了文本文件的所有行,如下所示:
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
我该怎么做?
答案 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']
相当强大。我什至不知道预编译会更快,除非您正在处理大量噩梦文件。