Python不是我最好的语言,所以我不是那么擅长为我的一些问题找到最有效的解决方案。我有一个非常大的字符串(来自一个30 MB的文件),我需要检查该文件是否包含一个较小的子字符串(此字符串只有几十个字符)。我目前的做法是:
if small_string in large_string:
# logic here
但这似乎效率很低,因为它会检查文件中每个可能的字符序列。我知道在换行符上只会有完全匹配,所以最好以列表形式读取文件并遍历该列表以匹配?
编辑:要澄清一些关于“仅在换行符上匹配”的混淆,这是一个例子:
small_string = "This is a line"
big_string = "This is a line\nThis is another line\nThis is yet another"
如果我没有错,in关键字将检查所有序列,而不仅仅是每一行。
答案 0 :(得分:12)
真的很慢吗?你说的是30MB字符串;让我们尝试更大的字符串:
In [12]: string="agu82934u"*50*1024*1024+"string to be found"
In [13]: len(string)
Out[13]: 471859218
In [14]: %timeit "string to be found" in string
1 loops, best of 3: 335 ms per loop
In [15]: %timeit "string not to be found" in string
1 loops, best of 3: 200 ms per loop
我不会说335毫秒是在450MB字符串中查找子字符串的时间。
答案 1 :(得分:9)
速度有多慢?我刚刚在170 MB字符串的末尾对一个唯一的字符串进行了a in b
测试。它在我的手指离开Enter键之前完成。
答案 2 :(得分:4)
您可以使用以下算法之一:
虽然我认为KMP效率更高,但实现起来却更复杂。第一个链接包含一些伪代码,这些代码应该很容易在python中实现。
您可以在此处查找替代方案:http://en.wikipedia.org/wiki/String_searching_algorithm
答案 3 :(得分:4)
说实话,我没有看到如何使它在比较中更加优化。但是,如果逐行读取文件,则可以使用更少的内存并减少使用I / O的时间:
has_small_string = False
for line in large_file:
if small_string in line:
has_small_string = True
break
if has_small_string:
# ... Your stuff here ...
这不是一项革命性的改进,如果真的需要内存中的大字符串,但它可能会有所帮助,那么它可能会变得更有用,所以我发帖了这里:))
答案 4 :(得分:2)
如果您只想检查该子字符串是否存在,
for line in open("file"):
if substring in line:
print "exists"
sys.exit() # or break to do some other stuff
答案 5 :(得分:1)
您是否暗示只有完整的一行会匹配? (您的编辑:仅在换行符上匹配示例)
然后我想象
for line in open('file').readlines():
if line==small_string:
return True
return False
IE,使用==比'in'更快 - 也许。如果in的底层实现捕获了搜索行和要搜索的字符串是相同的长度而只是尝试==本身的情况,我不会感到惊讶。
woudl会更好。
答案 6 :(得分:0)
small_string = "This is a line"
big_string = "This is a line This is another line\nThis is yet another"
test= big_string.split("This is a line" ,1)
if len(test)==2:
print "it`s there"
elif len(test)!=2:
print "it`s not"
答案 7 :(得分:-1)
我会依赖别人的快速实施:
import subprocess
from subprocess import STDOUT
import os
...
with open(os.devnull, 'w') as devnull:
if subprocess.call('grep %s "%s"' % (smallstring, file), shell=True, stdout=devnull, stderr=STDOUT) == 0:
pass #do stuff
无法在Windows上运行。
编辑:我担心grep返回0时它会发现某些东西。但我现在没有任何可用的shell,所以我无法测试它。