使用Python在一个.txt文件中搜索单词或短语列表(并显示上下文)
基本上如问题所述。我对Python相当陌生,喜欢通过看和做来学习 我想创建一个脚本,在文本文档(例如从新闻文章复制和粘贴的文本)中搜索某些单词或短语。理想情况下,单词和短语列表将存储在单独的文件中 在获得结果时,最好能了解结果的上下文。因此,它可能会在找到的每个搜索词前后打印出文本文件中的50个字符。如果它也能显示搜索词是在哪一行找到的,那就太酷了使用Python在一个.txt文件中搜索单词或短语列表(并显示上下文),python,search,text,Python,Search,Text,基本上如问题所述。我对Python相当陌生,喜欢通过看和做来学习 我想创建一个脚本,在文本文档(例如从新闻文章复制和粘贴的文本)中搜索某些单词或短语。理想情况下,单词和短语列表将存储在单独的文件中 在获得结果时,最好能了解结果的上下文。因此,它可能会在找到的每个搜索词前后打印出文本文件中的50个字符。如果它也能显示搜索词是在哪一行找到的,那就太酷了 任何关于如何编写此代码的指南,甚至代码示例都将不胜感激 从这样的事情开始。这段代码不是您所拥有的规范的精确解决方案,但它是一个很好的起点 impor
任何关于如何编写此代码的指南,甚至代码示例都将不胜感激 从这样的事情开始。这段代码不是您所拥有的规范的精确解决方案,但它是一个很好的起点
import sys
words = "foo bar baz frob"
word_set = set(words.split())
for line_number, line in enumerate(open(sys.argv[1])):
if words_set.intersection(line.split()):
print "%d:%s" % (line_number, line.strip())
以下是一些解释:
- 正在查找的单词最初存储在字符串中(第3行)。我将这个单词列表沿空格分开,并创建一组单词,以便更容易检查当前行中的任何单词是否在单词列表中找到。(集合上的成员检查为O(1),而列表上的成员检查为O(n))
- 在main for循环中,我打开输入文件(作为命令行参数传递),并使用
内置方法获取行号计数器和实际行enumerate
是存储命令行参数的数组sys.argv
始终是Python脚本的名称sys.argv[0]
- 在循环本身中,我取当前行,将其拆分为单个单词,然后再次创建一组单词。然后,我可以快速获取当前行中的单词集与我要查找的单词集的交点。如果交叉点有一个逻辑
值(即,如果它不是空的),我会打印行号和行号True
- 单词列表现在已在源代码中硬编码,但打开一个额外的文件(其名称已传入,例如,
),逐个读取单词并将其存储在一组中应该不会太难。请注意,您可以通过其sys.argv[2]
和add
方法扩展集合(而不是对列表有效的update
和append
)extend
- 显然,如果您使用短语而不是单词(如其中一条评论中所指出的),则上述方法不起作用。由于我假设您想要学习,并且不需要精确的解决方案,我只想说,如果您在一个集合中有短语,您可以通过说
来检查集合元素是否在一行中。这可以用来代替设置交叉点(当然,在这种情况下,不要将线拆分为单词)any(短语在一行中,短语在一组短语中)
- 如果要打印点击的上下文,可以使用两个额外变量(例如,
和prev\u line
)来存储前一行和下一行。在for循环中,您实际上将读取next\u line
,而不是下一行
,并且在for循环结束时,您应该注意将行
复制到行
,并将上一行
复制到下一行
行
- 跟踪上一行和下一行的一种更具Python风格的方法是创建一个Python生成器函数,该函数生成一个元组,每个元组由i-1项、i项和i+1项组成,每个i项都给定一个iterable(如文件)。不过,这是更高级的东西,因为您对Python还相当陌生,所以我认为最好稍后再使用它。但是,如果您感到好奇,执行此任务的生成器函数可能如下所示:
def context_generator(iterable): prev, current, next = None, None, None for element in iterable: prev, current, next = current, next, element if current is not None: yield prev, current, next if next is not None: yield current, next, None
\b
“单词边界”正则表达式模式中的元素——基于字符串处理的替代方案更是一个问题,例如,。split()
使用空格作为分隔符,从而使标点符号附加到相邻的单词上,这很麻烦,等等)
如果RE’s还可以,我会推荐如下内容:
import re
import sys
def main():
if len(sys.argv) != 3:
print("Usage: %s fileofstufftofind filetofinditin" % sys.argv[0])
sys.exit(1)
with open(sys.argv[1]) as f:
patterns = [r'\b%s\b' % re.escape(s.strip()) for s in f]
there = re.compile('|'.join(patterns))
with open(sys.argv[2]) as f:
for i, s in enumerate(f):
if there.search(s):
print("Line %s: %r" % (i, s))
main()
第一个参数是要查找单词或短语的文本文件(路径),每行一个,第二个参数是要查找单词或短语的文本文件(路径)。如果需要的话,可以很容易地使大小写搜索不敏感(可能只是选择性地基于命令行选项开关),等等
对不熟悉REs.的读者的一些解释:
模式
项中的\b
项确保不会出现意外匹配(如果您正在搜索“猫”或“狗”,您将不会看到“目录”或“失败者”的意外命中;您也不会错过“猫,微笑,逃跑”中的命中,因为您认为有“猫”这个词包括逗号;-)
|
项表示或
,例如,来自包含内容的文本文件(两行)
这将形成模式'\bcat\b |\bdog\b'
,该模式将定位“猫”或“狗”(作为独立单词,忽略标点符号,但拒绝较长单词中的点击)
re.escape
转义标点符号,因此标点符号按字面意思进行匹配,而不像re模式中通常具有的特殊含义。要打开输入文件,需要使用open
。此外,不需要将行中的单词转换为集合,也可以通过word\u set.intersection(line.split())在内部完成
@FogleBird@silenghost:谢谢你的评论。我采取了某种“迭代”的方法,而且我是即兴的
cat
dog