代码之家  ›  专栏  ›  技术社区  ›  SyncMaster

Python-如何在大文件中搜索字符串

  •  1
  • SyncMaster  · 技术社区  · 8 年前

    file_+0.txt, file_[]1.txt, file_~8.txt

    我想找到失踪的人 files_*.txt 直到某个数字。

    1 and 4

    asdffile_[0.txtsadfe
    asqwffile_~2.txtsafwe
    awedffile_[]2.txtsdfwe
    qwefile_*0.txtsade
    zsffile_+3.txtsadwe
    

    我写了一个Python脚本,我可以给它文件路径和一个数字,它会给我所有在这个数字之前丢失的文件名。

    我的程序适用于小文件。但当我给一个大文件(12MB)时,它的文件号可以达到10000,它只是挂起。

    这是我当前的Python代码

    #! /usr/bin/env/python
    import mmap
    import re
    
    def main():
        filePath = input("Enter file path: ")
        endFileNum = input("Enter end file number: ")
        print(filePath)
        print(endFileNum)
        filesMissing = []
        filesPresent = []
        f = open(filePath, 'rb', 0)
        s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
        for x in range(int(endFileNum)):
            myRegex = r'(.*)file(.*)' + re.escape(str(x)) + r'\.txt'
            myRegex = bytes(myRegex, 'utf-8')
            if re.search(myRegex, s):
                filesPresent.append(x)
            else:
                filesMissing.append(x)
        #print(filesPresent)
        print(filesMissing)
    
    if __name__ == "__main__":
        main()
    

    当我给出一个12MB的文件时,输出挂起,该文件可以包含从0到9999的文件

    $python findFileNumbers.py
    Enter file path: abc.log
    Enter end file number: 10000
    

    小文件的输出(与上述示例相同)

    $python findFileNumbers.py
    Enter file path: sample.log
    Enter end file number: 5
    [0, 2, 3]
    [1, 4]
    
    1. 我怎样才能使它适用于大文件?
    2. 有没有更好的方法来获得这些结果而不是Python脚本?

    提前感谢!

    3 回复  |  直到 8 年前
        1
  •  2
  •   balki    8 年前

    首先收集集合中现有的,然后寻找缺失的。

    my_regex = re.compile('.*file.*(\d+)\.txt.*')
    present_ones = set()
    for line in open(filepath):
        match = my_regex.match(line)
        if match:
           present_ones.add(int(match.group(1)))
    for num in range(...):
        if num not in present_ones:
            print("Missing" + num)
    

        2
  •  1
  •   Bill Bell    8 年前

    我建议您只需逐行阅读输入文件,并分析每一行的文件号。然后使用该文件号作为布尔数组的索引,最初设置为False。

    您不需要执行任何需要将文件存储在内存中的处理。这种方法适用于非常大的文件。

    #~ import mmap
    import re
    import numpy as np
    
    def main():
        #~ filePath = input("Enter file path: ")
        filePath = 'filenames.txt'
        #~ endFileNum = input("Enter end file number: ")
        endFileNum = 5
        print(filePath)
        print(endFileNum)
        found = np.zeros(1+endFileNum, dtype=bool)
        patt = re.compile(r'[^\d]+(\d+)')
        with open(filePath) as f:
            for line in f.readlines():
                r = patt.search(line).groups(0)[0]
                if r:
                    found[int(r)]=True
        print (found)
    
        #~ filesMissing = []
        #~ filesPresent = []
        #~ files = np.zeros[endFileNum, dtype=bool]
        #~ f = open(filePath, 'rb', 0)
        #~ s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
        #~ for x in range(int(endFileNum)):
            #~ myRegex = r'(.*)file(.*)' + re.escape(str(x)) + r'\.txt'
            #~ myRegex = bytes(myRegex, 'utf-8')
            #~ if re.search(myRegex, s):
                #~ filesPresent.append(x)
            #~ else:
                #~ filesMissing.append(x)
        #print(filesPresent)
        #~ print(filesMissing)
    
    if __name__ == "__main__":
        main()
    

    这将生成以下结果,您的 filesPresent filesMissing

    filenames.txt
    5
    [ True False  True  True False False]
    
        3
  •  1
  •   Community Mohan Dere    6 年前

    让我们看看你在这里实际做了什么:

    1. 内存映射文件。

    2. 对于每个数字


      b、 在整个文件中搜索正则表达式。

    这对于大量数据来说效率很低。而内存映射为您提供了一个字符串 对于文件来说,这不是魔术。您仍然可以在其中移动文件的加载块。同时,您正在对每个正则表达式进行传递,可能是对整个文件进行传递。正则表达式匹配也很昂贵。

    这里的解决方案是逐行通过文件。如果需要搜索大量数字,则应预编译正则表达式,而不是每个数字编译一次。要在一次传递中获得所有数字,您可以 set 在所有数字中,有一个是你想要的,叫做“失踪”,一个是空的 称为“发现”。每当你遇到一行数字,你就会把数字从“缺失”移到“找到”。

    filePath = input("Enter file path: ")
    endFileNum = int(input("Enter end file number: "))
    missing = set(range(endFileNum))
    found = set()
    regex = re.compile(r'file_.*?(\d+)\.txt')
    with open(filePath) as file:
        for line in file:
            for match in regex.finditer(line)
                num = int(match.groups(1))
                if num < endFileNum:
                    found.add(num)
    missing -= found
    

    注意,正则表达式使用 reluctant quantifier .*? 之后 file_ .*