我想用re实现几行python,首先操作一个字符串,然后用这个字符串作为regex搜索。我的字符串有 *
在他们中间,即。ab***cd
与 *
的任意长度。这样做的目的是在文档中进行regex搜索,提取任何符合起始和结束字符的行,中间有任意数量的字符,即ab12345cd,abbbcd,ab_fghfghfghcd,都是正向匹配。负匹配的例子。1abcd, agcd, bb111cd.
我想出了以下的重构码 [\s\S]*?
输入,而不是 *
's. 所以,我想从一个例子字符串中获取 ab***cd
到 ^ab[\s\S]*?cd
然后,我将用它来搜索一个文件的regex。
然后,我想在mmap中打开文件,使用regex搜索,然后将匹配的文件保存到文件中。
import re
import mmap
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
def searchFile(list_txt, raw_str):
search="^"+raw_str #add regex ^ newline operator
search_rgx=re.sub(r'\*+',r'[\\s\\S]*?',search) #replace * with regex function
#search file
with open(list_txt, 'r+') as f:
data = mmap.mmap(f.fileno(), 0)
results = re.findall(bytes(search_rgx,encoding="utf-8"),data, re.MULTILINE)
#save results
f1 = open('results.txt', 'w+b')
results_bin = b'\n'.join(results)
f1.write(results_bin)
f1.close()
print("Found "+str(file_len("results.txt"))+" results")
searchFile("largelist.txt","ab**cd")
现在,这在小文件中可以正常工作。但是当文件变大的时候(1gb的文本),我得到了这个错误。
Traceback (most recent call last):
File "c:\Programming\test.py", line 27, in <module>
searchFile("largelist.txt","ab**cd")
File "c:\Programming\test.py", line 21, in searchFile
results_bin = b'\n'.join(results)
MemoryError
首先,谁能帮我稍微优化一下代码?我是不是做了什么严重的错误?我使用了mmap,因为我知道我想看大文件,我想一行一行地读文件,而不是一次读完(因此有人建议使用mmap)。
也有人告诉我可以看看pandas库,以获得更多的数据操作。pandas的可以代替mmap吗?
谢谢你的帮助。你可以看出,我对python很陌生,所以很感激任何帮助。
那这样呢?在这种情况下,你需要的是一个用字符串表示的所有行的列表。下面的代码模拟了这种情况,产生了一个字符串列表。
import io
longstring = """ab12345cd
abbbcd
ab_fghfghfghcd
1abcd
agcd
bb111cd
"""
list_of_strings = io.StringIO(longstring).read().splitlines()
list_of_strings
输出
['ab12345cd', 'abbbcd', 'ab_fghfghfghcd', '1abcd', 'agcd', 'bb111cd']
这是最重要的部分
s = pd.Series(list_of_strings)
s[s.str.match('^ab[\s\S]*?cd')]
产出
0 ab12345cd
1 abbbcd
2 ab_fghfghfghcd
dtype: object
编辑2: 试试这个: (我不明白你为什么要把它作为一个函数,但我已经这样做了,因为你在评论中做了什么。)
def newsearch(filename):
with open(filename, 'r', encoding="utf-8") as f:
list_of_strings = f.read().splitlines()
s = pd.Series(list_of_strings)
s = s[s.str.match('^ab[\s\S]*?cd')]
s.to_csv('output.txt', header=False, index=False)
newsearch('list.txt')
基于分块的方法
import os
def newsearch(filename):
outpath = 'output.txt'
if os.path.exists(outpath):
os.remove(outpath)
for chunk in pd.read_csv(filename, sep='|', header=None, chunksize=10**6):
chunk = chunk[chunk[0].str.match('^ab[\s\S]*?cd')]
chunk[0].to_csv(outpath, index=False, header=False, mode='a')
newsearch('list.txt')
一个ask方法
import dask.dataframe as dd
def newsearch(filename):
chunk = dd.read_csv(filename, header=None, blocksize=25e6)
chunk = chunk[chunk[0].str.match('^ab[\s\S]*?cd')]
chunk[0].to_csv('output.txt', index=False, header=False, single_file = True)
newsearch('list.txt')
你正在进行逐行处理,所以你要避免在内存中积累数据。常规的文件读写在这里应该可以很好地工作。mmap
是由虚拟内存支持的,但当你读取它时,它必须变成真实的内存。积累的结果是 findall
也是一个内存占用者。试试这个作为替代方案。
import re
# buffer to 1Meg but any effect would be modest
MEG = 2**20
def searchFile(filename, raw_str):
# extract start and end from "ab***cd"
startswith, endswith = re.match(r"([^\*]+)\*+?([^\*]+)", raw_str).groups()
with open(filename, buffering=MEG) as in_f, open("results.txt", "w", buffering=MEG) as out_f:
for line in in_f:
stripped = line.strip()
if stripped.startswith(startswith) and stripped.endswith(endswith):
out_f.write(line)
# write test file
test_txt = """ab12345cd
abbbcd
ab_fghfghfghcd
1abcd
agcd
bb111cd
"""
want = """ab12345cd
abbbcd
ab_fghfghfghcd
"""
open("test.txt", "w").write(test_txt)
searchFile("test.txt", "ab**cd")
result = open("results.txt").read()
print(result == want)
我不知道你认为用这个方法打开输入文件会有什么好处 mmap
但由于每个必须匹配的字符串都是以换行来定界的 (根据你的评论),我将使用下面的方法 (注意,它是 Python,但特意保留为伪代码)。
with open(input_file_path, "r") as input_file:
with open(output_file_path, "x" as output_file:
for line in input_file:
if is_match(line):
print(line, file=output_file)
可能会调整 endline
参数的 print
函数来满足您的需求。
这样,结果在生成时就会被写入,你就可以避免有大量的 results
而且,你不需要关注换行,只需要关注每行是否匹配。只需要关注每行是否匹配。