我试图在一个文本文件中设置范围,以便将搜索结果与特定的chap关联起来

2024-06-09 11:11:52 发布

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

我知道有更可行的方法来解决这个问题(db:mysql,oracle等),我有一个mysql数据库文件(KJV Bible),可以通过PHP代码搜索。但是,我想打开圣经.txt在Python文件中搜索特定的字符串并返回行和行号。另外,(对我来说是个挑战)我还想返回找到这行代码的书(从一个平面文件)。我一直在阅读并试图更熟悉Python。不幸的是,我仍然缺乏有效解决问题的知识和技能。我想如果我使用range方法来设置章节的开头和结尾(代表行号),我可以为每本书/章节硬编码一个名称(例如。。范围(384805)这个范围之间的所有线都是创世纪)。这似乎行得通,我只试了几本书。但是代码非常冗长(elif语句)。有人知道更有效的方法吗?下面是我编写的代码示例,尝试了几本书合资企业.txt文件可能是obtained from Project Gutenberg。在

 import os
 import sys
 import re

 word_search = raw_input(r'Enter a word to search: ')
 book = open("KJV.txt", "r")
 regex = re.compile(word_search)
 bibook = ''

 for i, line in enumerate(book.readlines()):
     result = regex.search(line)
     ln = i
     if result:
         if ln in range(36, 4809):
            bibook = 'Genesis'
         elif ln in range(4812, 8859):
            bibook = 'Exodus'
         elif ln in range(8867, 11741):
            bibook =  'Leviticus'
         elif ln in range(11749, 15713):
            bibook = 'Numbers'

         template = "\nLine: {0}\nString: {1}\nBook: {2}\n"
         output = template.format(ln, result.group(), bibook)
         print output

Tags: 文件方法代码inimporttxtsearchmysql
3条回答

这是一个非常坚实的开始。不过,我有一些建议。在

首先,使用readlines有点效率低下。readlines从文件中创建一个新的行列表——它将整个文件存储在内存中。但您不必这样做;如果您只想遍历文件中的行,您可以说for line in file,或者在您的例子中:

for i, line in enumerate(book):

或者,如果确实要将文件存储在内存中(可能是为了重复搜索),请将readlines的结果保存到一个变量中:

^{pr2}$

您也可以使用read将文本存储为单个字符串,但在这种情况下这并没有太大帮助,因为您仍然需要拆分它:

booktxt = book.read()
booklines = book.splitlines() #
for i, line in enumerate(booklines)

其次,我想说的是,与其使用i作为索引变量,然后将其单独保存到ln,不如预先使用一个有意义的变量名。ln很好,line_number更清晰但冗长,lineno是一个很好的折衷方案。既然我们都知道它的意思,我们还是在这里继续讨论ln。在

for ln, line in enumerate(book):

第三,正如utdemir在评论中指出的那样,您不需要为此使用regex。如果你想让你的用户能够输入更复杂的搜索,这可能是有意义的,但是REs太复杂了,以至于它们会产生一个可疑的默认ui。我只需要使用in进行简单的子字符串匹配,如:

    if word_search in line: 

其余的if语句都很好,在某些情况下,这是最好的做法。然而,通常在需要case语句的情况下,使用字典实际上更好。当然,这里有射程,所以我们得聪明一点。在

让我们从一本词典开始吧。很明显,这应该在循环之前,这样我们就不会每次都重新定义字典了。在

first_lines = {36: 'Genesis', 4812: 'Exodus', 8867: 'Leviticus', 11749: 'Numbers'}

现在我们必须将ln映射到这些字典值之一。但是很有可能ln不等于上面的任何一个数字,所以我们不能直接把它插入字典。我们可以使用一个for循环来迭代字典键(for key in first_lines),将上一个键存储在prev_key中,测试{},如果是,返回prev_key。但实际上在python中有一种更好的方法。我们使用内置函数filter或列表理解来从列表中删除大于ln的值,而不是编写普通循环。然后我们找到max。在

first_line = max(filter(lambda l: l < ln, first_lines))

这里first_lines的作用类似于其键的无序列表;通常,您可以像遍历列表一样在字典中迭代键,但要注意的是,这些键可以采用任何顺序。lambda是一种定义短函数的方法:该函数以x为参数,并返回{}的结果。我们必须这样做,因为filter想要一个函数作为它的第一个参数。它返回一个列表,其中包含来自first_lines的所有值,这些值给出一个True结果。在

由于这可能有点难以阅读,特别是当涉及lambda时,我们最好在这里使用列表理解。列表理解对大多数人来说都是可读和直观的。在

first_line = max([l for l in first_lines if l < ln])

在这种情况下,我们甚至可以省去括号,因为我们直接将它传递给函数。Python将其解释为一种称为“生成器表达式”的东西,类似于列表理解,但会动态计算值,而不是预先将它们存储在列表中。在

first_line = max(l for l in first_lines if l < ln)

现在要想得到这本书的名字,您只需使用first_line作为键:

bibook = first_lines[first_line]

最终结果:

import os
import sys
import re

word_search = raw_input(r'Enter a word to search: ')
book = open("KJV.txt", "r")
first_lines = {36: 'Genesis', 4812: 'Exodus', 8867: 'Leviticus', 11749: 'Numbers'}

for ln, line in enumerate(book):
    if word_search in line:
        first_line = max(l for l in first_lines if l < ln)
        bibook = first_lines[first_line]

        template = "\nLine: {0}\nString: {1}\nBook: {2}\n"
        output = template.format(ln, word_search, bibook)
        print output
     if ln in range(36, 4809):
        bibook = 'Genesis'
     elif ln in range(4812, 8859):
        bibook = 'Exodus'
     elif ln in range(8867, 11741):
        bibook =  'Leviticus'
     elif ln in range(11749, 15713):
        bibook = 'Numbers'

最好写为:

^{pr2}$

只是稍微改变了代码的版本。在

word_search = raw_input(r'Enter a word to search: ')

with open("KJV.txt", "r") as book:
    #using with is always better when messing with files.
    bibook = ''
    for pos, line in enumerate(book):
    #a file object is already an iterable, so i don't think we need readlines.
        if result in line:
        #if result is always in ranges in your question, no need to check other limits.
        #also comparision operators is a lot faster than in.
            if pos < 4809:
                bibook = 'Genesis'
            elif pos < 8859:
                bibook = 'Exodus'
            elif pos < 11741:
                bibook = 'Leviticus'
            else:
                bibook = 'Numbers'
            #you can use string templates, but i think no need for that
            out = "\nLine: {0}\nString: {1}\nBook: {2}".format(
                                            pos, line, book)

            print(out)

编辑:

现在我读了你的示例文件。我认为把第一个“1:2”部分分开,用它来学习书和行号会是一个更好的选择。在

相关问题 更多 >