如何编写一个简单的Python解析脚本?

2024-05-13 03:13:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我所做的大部分工作涉及编写简单的解析脚本,从一个文件读取搜索项,然后逐行搜索另一个文件。找到搜索项后,该行(有时还有下一行)将写入另一个输出文件。我使用的代码是基本的,很可能是粗糙的。

#!/usr/bin/env python

data = open("data.txt", "r")
search_terms = ids.read().splitlines()
data.close()
db = open("db.txt", "r")

output = open("output.txt", "w")

for term in search_terms:
    for line in db:
        if line.find(term) > -1:
            next_line = db.next()
            output.write(">" + head + "\n" + next_line)
            print("Found %s" % term)

这里有一些问题。首先,我不认为这是最有效和最快的逐行搜索,但我不完全确定。其次,我经常遇到光标位置的问题,当找到搜索项时,光标不会重置到文件的开头。第三,虽然我通常确信所有的术语都可以在数据库中找到,但很少有时候我不能确定,所以每当它遍历整个数据库而找不到术语时,我想写入另一个文件。我试过添加一个代码片段来计算数据库的行数,因此如果find()函数到达最后一行而找不到术语,那么它会输出到另一个“找不到”文件,但我无法正确地获取elif和else循环。

总的来说,我只想得到任何提示或修正,使这类脚本更加高效和健壮。

谢谢。


Tags: 文件代码txt脚本数据库outputdbsearch
3条回答

除非是一个很大的文件,为什么不逐行迭代呢?如果输入文件的大小是计算机可用资源(内存)的某个重要部分,那么您可能需要查看缓冲输入和其他更低级的计算机工作抽象。但如果你在一台相对现代的机器上谈论的是几百兆字节或更少,那就让计算机来做计算吧;)

你可能想马上养成使用内置上下文管理器的习惯。例如,在代码片段中,您没有对output.close()的调用。

with open('data.txt', 'r') as f_in:
    search_terms = f_in.read().splitlines()

现在search_terms是一个列表的句柄,它将data.txt中的每一行作为字符串(但删除换行符)。而data.txt由于with而关闭。

事实上,我也会用db.txt文件来实现这一点。

with open('db.txt', 'r') as f_in:
    lines = f_in.read().splitlines()

上下文管理器很酷。

顺便说一句,你可以现在打开你的目标文件,并在它打开的时候进行解析和结果跟踪,但是我喜欢让尽可能多的文件尽可能长时间地关闭。

我建议在循环外部设置最大的对象,我猜是db.txtcontents。最外层的循环通常只迭代一次,所以最好把最大的东西放在那里。

results = []
for i, line in enumerate(lines):
    for term in search_terms:
        if term in line:
            # Use something not likely to appear in your line as a separator
            # for these "second lines". I used three pipe characters, but
            # you could just as easily use something even more random
            results.append('{}|||{}'.format(line, lines[i+1]))

if results:
    with open('output.txt', 'w') as f_out:
        for result in results:
            # Don't forget to replace your custom field separator
            f_out.write('> {}\n'.format(result.replace('|||', '\n')))
else:
    with open('no_results.txt', 'w') as f_out:
        # This will write an empty file to disk
        pass

这种方法的好处是,db.txt中的每一行对于search_terms中的每个搜索项都检查一次。但是,缺点是,任何一行都将记录其包含的每个搜索词,即,如果其中包含三个搜索词,则该行将在您的output.txt中出现三次。

所有的文件都神奇地关闭了。

上下文管理器很酷。

祝你好运!

search_terms将整个data.txt保存在内存中。总的来说不好,但在这种情况下也不太坏。

逐行查找是不够的,但如果情况简单,文件不太大,这不是什么大不了的事。如果你想提高效率,你应该对data.txt文件进行排序,并将其放到树状结构中。这取决于里面的数据。

在使用next之后,必须使用seek将指针移回。

显然,这里最简单的方法是生成两个行列表并使用类似于in的搜索:

`db = open('db.txt').readlines()
 db_words = [x.split() for x in db]
 data = open('data.txt').readlines()
 print('Lines in db {}'.format(len(db)))
 for item in db:
     for words in db_words:
         if item in words:
            print("Found {}".format(item))`

你的关键问题是,你可能按错误的顺序循环——在你发布的代码中,你总是会用尽db来寻找第一个术语,因此在第一次通过外部for循环db之后,就不会有更多的行要读了,也不会找到其他术语。

其他改进包括使用with语句来保证文件关闭,使用set来跟踪未找到的搜索项。(在您发布的代码中也有输入错误,例如以data的形式打开文件,然后以ids的形式读取它)。

例如,比如说:

with open("data.txt", "r") as data:
    search_terms = data.read().splitlines()

missing_terms = set(search_terms)

with open("db.txt", "r") as db, open("output.txt", "w") as output:
    for line in db:
        for term in search_terms:
            if term in line:
                missing_terms.discard(term)
                next_line = db.next()
                output.write(">" + head + "\n" + next_line)
                print("Found {}".format(term))
                break

if missing_terms:
    diagnose_not_found(missing_terms)

在这里,diagnose_not_found函数做任何需要做的事情来警告用户缺少术语。

这里嵌入了一些假设,比如你不在乎在你找到上一个或下一个搜索词的行中是否存在其他搜索词;如果不适用,它们可能需要大量的工作来修复,这将要求你用一个非常完整和明确的规范列表来编辑你的Q。

如果您的db实际上足够小,可以轻松地放入内存,那么一次性地将其全部作为行列表放入内存中,可以更方便地容纳更苛刻的规范(在这种情况下,您可以轻松地来回移动,而在文件上迭代意味着您一次只能前进一行),因此如果您的规范确实更高要求也请澄清这一关键条件是否成立,或者更确切地说,您需要这个脚本来处理可能非常庞大的db文件(比如千兆字节以上的大小,以便不“舒适地适应内存”,当然这取决于您的平台)。

相关问题 更多 >