如何更快地在文本文件中搜索字符串

fda*_*bhi 6 python pandas

我想搜索保存在文件夹中的数千个文本文件(可能有多达100k文本文件,每个大小范围从1 KB到100 MB)的字符串列表(列表中包含2k到10k字符串)输出匹配的文本文件名的csv文件.

我已经开发了一个代码来完成所需的工作,但2000字符串需要大约8-9个小时来搜索大约2000个大小约为2.5 GB的文本文件.

此外,通过使用此方法,系统的内存被消耗,因此有时需要将2000个文本文件拆分为较小的批处理以运行代码.

代码如下(Python 2.7).

# -*- coding: utf-8 -*-
import pandas as pd
import os

def match(searchterm):
    global result
    filenameText = ''
    matchrateText = ''
    for i, content in enumerate(TextContent):
        matchrate = search(searchterm, content)
        if matchrate:
            filenameText += str(listoftxtfiles[i])+";"
            matchrateText += str(matchrate) + ";"
    result.append([searchterm, filenameText, matchrateText])


def search(searchterm, content):
    if searchterm.lower() in content.lower():
        return 100
    else:
        return 0


listoftxtfiles = os.listdir("Txt/")
TextContent = []
for txt in listoftxtfiles:
    with open("Txt/"+txt, 'r') as txtfile:
        TextContent.append(txtfile.read())

result = []
for i, searchterm in enumerate(searchlist):
    print("Checking for " + str(i + 1) + " of " + str(len(searchlist)))
    match(searchterm)

df=pd.DataFrame(result,columns=["String","Filename", "Hit%"])
Run Code Online (Sandbox Code Playgroud)

下面的示例输入.

字符串列表 -

["Blue Chip", "JP Morgan Global Healthcare","Maximum Horizon","1838 Large Cornerstone"]
Run Code Online (Sandbox Code Playgroud)

文本文件 -

通常的文本文件包含由\n分隔的不同行

下面的示例输出.

String,Filename,Hit%
JP Morgan Global Healthcare,000032.txt;000031.txt;000029.txt;000015.txt;,100;100;100;100;
Blue Chip,000116.txt;000126.txt;000114.txt;,100;100;100;
1838 Large Cornerstone,NA,NA
Maximum Horizon,000116.txt;000126.txt;000114.txt;,100;100;100;
Run Code Online (Sandbox Code Playgroud)

如上例所示,第一个字符串在4个文件中匹配(由;分隔),第二个字符串在3个文件中匹配,第三个字符串在任何文件中都不匹配.

有没有更快的方式搜索没有任何文本文件的分裂?

agt*_*ver 1

您的代码会在内存中推送大量数据,因为您将所有文件加载到内存中然后搜索它们。

除了性能之外,您的代码还可以进行一些清理。尝试编写尽可能自主的函数,而不依赖于全局变量(用于输入或输出)。

我使用列表理解重写了您的代码,它变得更加紧凑。

# -*- coding: utf-8 -*-
from os import listdir
from os.path import isfile

def search_strings_in_files(path_str, search_list):
    """ Returns a list of lists, where each inner list contans three fields:
    the filename (without path), a string in search_list and the
    frequency (number of occurences) of that string in that file"""

    filelist = listdir(path_str)

    return [[filename, s, open(path_str+filename, 'r').read().lower().count(s)]
        for filename in filelist
            if isfile(path_str+filename)
                for s in [sl.lower() for sl in search_list] ]

if __name__ == '__main__':
    print search_strings_in_files('/some/path/', ['some', 'strings', 'here'])
Run Code Online (Sandbox Code Playgroud)

我在这段代码中使用的机制:

  • 列表理解循环思考 search_lists 并遍历文件。
  • 复合语句仅循环遍历目录中的文件(而不循环子目录)。
  • 方法链接直接调用返回对象的方法。

阅读列表理解的提示:尝试从下到上阅读,因此:

  • 我使用列表理解将 search_list 中的所有项目转换为 lower 。
  • 然后我循环该列表 ( for s in...)
  • if isfile...然后我使用复合语句 ( )过滤掉不是文件的目录条目
  • 然后我循环遍历所有文件 ( for filename...)
  • 在第一行中,我创建了包含三个项目的子列表:
    • 文件名
    • s,即小写搜索字符串
    • 用于打开文件、读取其所有内容、将其转换为小写并计算 s 出现次数的方法链式调用。

该代码使用了“标准”Python 函数中的所有功能。如果您需要更高的性能,您应该研究专门的库来完成此任务。