python - 我正在尝试在文本文件中设置范围,以便将搜索结果与特定章节相关联

标签 python range

我知道有更可行的方法来解决这个问题(数据库:mysql,oracle等...),并且我有一个mysql db文件(KJV Bible),我可以通过PHP代码搜索。但是,我想在 Python 中打开 Bible.txt 文件并搜索某些字符串并返回行和行号。此外,(对我来说是一个挑战)我还想归还找到该行的书(来自平面文件)。我一直在阅读并试图更加熟悉Python。不幸的是,我仍然缺乏有效和高效解决问题的知识和技能。这是我想到的:我认为如果我使用 range 方法来设置章节的开头和结尾(代表行号),我可以为每本书/章节硬编码一个名称(例如.. range( 38, 4805)此范围之间的所有线都是创世记)。这似乎有效;我只尝试了几本书。但代码非常冗长(elif 语句)。有谁知道更有效的方法?下面是我为尝试几本书而编写的代码示例,KJV.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

最佳答案

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

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

for i, line in enumerate(book):

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

booklines = book.readlines()
for i, line in enumerate(booklines):

您还可以使用 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 在评论中指出的那样,您实际上并不需要正则表达式。如果您希望用户能够输入更复杂的搜索,那么这可能是有意义的,但 RE 足够复杂,以至于它们会产生一个有问题的默认 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 中,测试是否 ln > key ,如果是,则返回 prev_key 。但实际上有一种更好的方法可以用 python 来实现。我们没有编写普通的循环,而是使用内置函数 filter 过滤列表。或列表理解,从列表中删除大于 ln 的值。然后我们找到max .

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

这里first_lines其行为就像一个无序列表的键;一般来说,您可以像遍历列表一样迭代字典中的键,但需要注意的是键可以采用任何顺序。 lambda是一种定义短函数的方法:此函数采用 x作为参数并返回 x < ln 的结果。我们必须这样做,因为 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

关于python - 我正在尝试在文本文件中设置范围,以便将搜索结果与特定章节相关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6642563/

相关文章:

Excel VBA 如何选择可变的单元格范围

ios - 从字符串中提取图像的URL

python - Boto "get byte range"返回超过预期

c - 如何在恒定时间内检查一组非重叠范围内的范围

javascript - 获取输入类型范围的值

python - 从字符串中删除数字

python - 使用 Groupby 对象进行计算 Pandas

python - 将来自 selenium_webdriver(chrome) 的流量绑定(bind)到特定的网络接口(interface)/隧道

python - 在 Python 中解析制表符分隔的文件

python - 使用 Python lxml 删除处理指令