在Python中搜索TXT文件
我是一名新手程序员,我们正在做一个研究生英语项目,目标是解析一个非常大的字典文本文件(500 MB)。这个文件里有类似HTML的标签。我有179个作者标签,比如"[A>]Shakes.[/A]"代表莎士比亚,我需要做的就是找到每个标签出现的地方,然后把这个标签和后面的内容写下来,直到遇到"[/W]"为止。
我遇到的问题是,使用readlines()的时候出现了内存错误(我猜是因为文件太大了)。我能找到匹配的内容(但只找到一次),却无法继续查找下一个匹配。任何人能提供的帮助我都非常感激。
文本文件里没有换行符,我觉得这可能是导致问题的原因。这个问题已经解决了。我想分享一下有效的代码:
with open('/Users/Desktop/Poetrylist.txt','w') as output_file:
with open('/Users/Desktop/2e.txt','r') as open_file:
the_whole_file = open_file.read()
start_position = 0
while True:
start_position = the_whole_file.find('<A>', start_position)
if start_position < 0:
break
start_position += 3
end_position = the_whole_file.find('</W>', start_position)
output_file.write(the_whole_file[start_position:end_position])
output_file.write("\n")
start_position = end_position + 4
6 个回答
1
你在使用readlines()的时候遇到了内存错误,这是因为你要读取的文件太大,超出了你的内存能处理的范围。由于这个文件是XML格式的,你可以使用iterparse()来逐步读取,这样就不会占用太多内存。下面是我用来解析维基百科数据的代码:
for event, elem in parser:
if event == 'start' and root == None:
root = elem
elif event == 'end' and elem.tag == namespace + 'title':
page_title = elem.text
#This clears bits of the tree we no longer use.
elem.clear()
elif event == 'end' and elem.tag == namespace + 'text':
page_text = elem.text
#Clear bits of the tree we no longer use
elem.clear()
#Now lets grab all of the outgoing links and store them in a list
key_vals = []
#Eliminate duplicate outgoing links.
key_vals = set(key_vals)
key_vals = list(key_vals)
count += 1
if count % 1000 == 0:
print str(count) + ' records processed.'
elif event == 'end' and elem.tag == namespace + 'page':
root.clear()
大致的工作原理是这样的:
我们创建一个解析器来逐步处理文档。
在循环文档的每个元素时,我们查找你需要的标签(在你的例子中是'A')。
我们把找到的数据存起来并进行处理。处理完的元素会被清除,因为在处理文档的过程中,这些元素会一直占用内存,所以我们想要删除那些不再需要的内容。
3
打开文件后,可以像这样逐行读取:
input_file = open('huge_file.txt', 'r')
for input_line in input_file:
# process the line however you need - consider learning some basic regular expressions
这样做可以让你按需逐行处理文件,而不是一次性把整个文件都加载到内存里。
2
我对正则表达式不太了解,但其实你可以不用它们来解决这个问题,使用字符串的方法 find() 和行切片就可以了。
answer = ''
with open('yourFile.txt','r') as open_file, open('output_file','w') as output_file:
for each_line in open_file:
if each_line.find('[A>]'):
start_position = each_line.find('[A>]')
start_position = start_position + 3
end_position = each_line[start_position:].find('[/W]')
answer = each_line[start_position:end_position] + '\n'
output_file.write(answer)
让我来解释一下具体是怎么回事:
- 首先,创建一个空的“列表”,用 = []。这个列表用来存放你的答案。
- 使用 with... 语句。这可以让你把文件打开,并给它起个别名(我叫它 open_file)。这样做的好处是,无论程序运行得好不好,文件都会自动关闭。
- 我们用 'for line in file:' 这种方式来逐行处理文件。'line' 这个变量可以随便命名(比如 for x in file,或者 for pizza in file),它会包含每一行的内容,都是字符串。当文件读完了,它会自动停止。
- 'if each_line.find('[A>]'):' 这个语句就是用来检查这一行里是否有开始标签。如果没有,那么后面缩进的代码就不会执行,循环会重新开始,继续处理下一行。
- 我们使用字符串切片,可以把我们想要的部分切出来。具体做法是先找到开始标签的位置(我们已经知道它在这一行里),然后再找到结束标签的位置。找到这两个位置后,我们就可以简单地切出我们需要的部分。
- 我在位置上做了两处调整。第一,我在开始位置上加了 3,这样就跳过了 [A>],所以输出的就变成了 'THIS IS MY STRING...' 而不是 '[A>] THIS IS MY STRING...'。然后我在 [A>] 标签后面找到了结束位置,以防这一行中 [/W] 标签出现多次。
- 我们把答案设置为字符串切片的结果,并加上一个换行符('\n'),这样每个字符串就会单独占一行。我们使用输出方法 .write('stringToWrite') 来逐个写入每个字符串。