如何使用Python结合正则表达式和字符串/文件操作在文本文件中搜索模式并存储模式的实例?

68
所以本质上我正在寻找一个文本文件中两个尖括号内的4位代码。我知道我需要打开文本文件然后逐行解析,但是我不确定在检查“for line in file”之后如何构建我的代码结构。
我认为我可以通过某种方式进行拆分、剥离或者划分,但是我还编写了一个正则表达式,我使用compile对其进行了编译,所以如果返回匹配对象,我不认为我可以将其与那些基于字符串的操作一起使用。而且我不确定我的正则表达式是否足够贪婪...
我希望将所有找到的这些命中的实例作为字符串存储在元组或列表中。
这是我的正则表达式:
regex = re.compile("(<(\d{4,5})>)?")

考虑到它目前还相当基础,我认为不需要包含太多的代码。


2
你的文件太大了,一次性将整个文件存入内存中会导致内存不足吗? - Josiah
好的,这个的最终用途是返回一个列表或元组的模块,可以进行检查吗?所以,我不确定,但那是我想要的最终用途。 - Carl Carlson
有一个函数re.findall(),它返回文件中所有匹配项的列表,因此如果您将文件读入字符串(.read()),则可以在其上运行该函数并获得匹配对象的列表。但是,如果文件太大而无法放入内存,则需要逐行读取它(或以其他方式拆分它)。 - Josiah
我发现这个文件大小为651 kb,但如果可能的话,我想限制使用过多的内存。我听说逐行处理更加安全,你怎么看? - Carl Carlson
一个文件必须有几个GB的大小才会成为问题。逐行处理的问题在于,你的匹配只会是你读取的每一行内的索引,而不是整个文件的索引。你可以解决这个问题,但这可能并不必要。 - Josiah
2个回答

75
import re
pattern = re.compile("<(\d{4,5})>")

for i, line in enumerate(open('test.txt')):
    for match in re.finditer(pattern, line):
        print 'Found on line %s: %s' % (i+1, match.group())

关于正则表达式的一些说明:

  • 如果你只想匹配数字本身而不是带有尖括号的数字,那么你不需要在末尾加上?以及外层的(...)
  • 它匹配尖括号之间的4或5位数字

更新: 理解正则表达式中的匹配捕获可能会有所不同。上面代码片段中的正则表达式匹配带有尖括号的数字,但我要求仅捕获内部数字,不包括尖括号。

更多有关Python正则表达式的信息可以在这里找到: 正则表达式指南


你说的outer是什么意思?你是在说我可以匹配尖括号之间的所有4-5位数字吗?因为这正是我想做的,只是我原本计划包括尖括号进行匹配,然后迭代使用rsplit和lsplit。 - Carl Carlson
@CarlCarlson:请比较一下你的正则表达式和我的。我只在数字周围放置了捕获括号(...)。而你在数字和尖括号周围都放置了捕获括号。因此,你的匹配将返回两者 - 而你只需要第一个。如果我理解正确的话,请参见我的答案更新。 - Eli Bendersky
我认为我对匹配和捕获有了更好的理解,但是为了明确起见,您并不意味着我要使用锚定,对吗?因为我只想要在尖括号之间的数字实例。 - Carl Carlson
不确定锚定与此有何关系。 - Eli Bendersky
2
@CarlCarlson:总的来说,给自己一个好处,花20分钟阅读http://docs.python.org/library/re.html——这20分钟将会多次回报。 - Eli Bendersky

40

一次性批量读取:

import re

textfile = open(filename, 'r')
filetext = textfile.read()
textfile.close()
matches = re.findall("(<(\d{4,5})>)?", filetext)

逐行解释:

import re

textfile = open(filename, 'r')
matches = []
reg = re.compile("(<(\d{4,5})>)?")
for line in textfile:
    matches += reg.findall(line)
textfile.close()

但是,再次强调,除非您添加了偏移计数器,否则返回的匹配结果除了计数之外将没有任何用处:

import re

textfile = open(filename, 'r')
matches = []
offset = 0
reg = re.compile("(<(\d{4,5})>)?")
for line in textfile:
    matches += [(reg.findall(line),offset)]
    offset += len(line)
textfile.close()

但是一次性读取整个文件仍然更加合理。


什么是偏移计数器,它的目的是什么?为什么我不能调用返回列表的模块并检查列表中的字符串是否与另一个字符串匹配? - Carl Carlson
1
哦,我没有理解原始问题,如果这就是你想做的事情,偏移量计数器是不必要的。我以为你想知道字符串出现在文件中的位置,对此我表示歉意。 - Josiah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接