在Python中搜索TXT文件

1 投票
6 回答
850 浏览
提问于 2025-04-16 22:04

我是一名新手程序员,我们正在做一个研究生英语项目,目标是解析一个非常大的字典文本文件(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()

大致的工作原理是这样的:

  1. 我们创建一个解析器来逐步处理文档。

  2. 在循环文档的每个元素时,我们查找你需要的标签(在你的例子中是'A')。

  3. 我们把找到的数据存起来并进行处理。处理完的元素会被清除,因为在处理文档的过程中,这些元素会一直占用内存,所以我们想要删除那些不再需要的内容。

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)

让我来解释一下具体是怎么回事:

  1. 首先,创建一个空的“列表”,用 = []。这个列表用来存放你的答案。
  2. 使用 with... 语句。这可以让你把文件打开,并给它起个别名(我叫它 open_file)。这样做的好处是,无论程序运行得好不好,文件都会自动关闭。
  3. 我们用 'for line in file:' 这种方式来逐行处理文件。'line' 这个变量可以随便命名(比如 for x in file,或者 for pizza in file),它会包含每一行的内容,都是字符串。当文件读完了,它会自动停止。
  4. 'if each_line.find('[A>]'):' 这个语句就是用来检查这一行里是否有开始标签。如果没有,那么后面缩进的代码就不会执行,循环会重新开始,继续处理下一行。
  5. 我们使用字符串切片,可以把我们想要的部分切出来。具体做法是先找到开始标签的位置(我们已经知道它在这一行里),然后再找到结束标签的位置。找到这两个位置后,我们就可以简单地切出我们需要的部分。
  6. 我在位置上做了两处调整。第一,我在开始位置上加了 3,这样就跳过了 [A>],所以输出的就变成了 'THIS IS MY STRING...' 而不是 '[A>] THIS IS MY STRING...'。然后我在 [A>] 标签后面找到了结束位置,以防这一行中 [/W] 标签出现多次。
  7. 我们把答案设置为字符串切片的结果,并加上一个换行符('\n'),这样每个字符串就会单独占一行。我们使用输出方法 .write('stringToWrite') 来逐个写入每个字符串。

撰写回答