Python中的快速多重搜索和替换

Python中的快速多重搜索和替换,python,regex,search,replace,Python,Regex,Search,Replace,对于单个大文本(~4GB),我需要搜索约100万个短语,并用补充短语替换它们。原始文本和替换文本都可以很容易地放入内存中。简单的解决方案实际上需要几年才能完成,因为一次更换大约需要一分钟 朴素的解决方案: for search, replace in replacements.iteritems(): text = text.replace(search, replace) 使用re.sub的正则表达式方法速度较慢: for search, replace in replacement

对于单个大文本(~4GB),我需要搜索约100万个短语,并用补充短语替换它们。原始文本和替换文本都可以很容易地放入内存中。简单的解决方案实际上需要几年才能完成,因为一次更换大约需要一分钟

朴素的解决方案:

for search, replace in replacements.iteritems():
    text = text.replace(search, replace)
使用
re.sub
的正则表达式方法速度较慢:

for search, replace in replacements.iteritems():
    text = re.sub(search, replace, text)
无论如何,这似乎是一个伟大的地方使用博耶摩尔字符串,或阿霍科拉西克;但是这些方法通常只用于搜索字符串,而不是替换字符串

或者,任何能够快速实现这一点的工具(Python之外的工具)也将受到欢迎


谢谢

在python之外,
sed
通常用于这类事情

例如(摘自),要将sue.txt文件中的单词丑陋替换为美丽:

sed -i 's/ugly/beautiful/g' /home/bruno/old-friends/sue.txt
您还没有发布任何代码评测,在进行任何过早的优化之前,您应该尝试一些计时。搜索和替换4GB文件中的文本是一项计算密集型操作

备选方案 问:我应该这样做吗-

您将在下面讨论在10毫秒内完成整个维基百科语料库的搜索和替换。这敲响了一些警钟,因为它听起来不像伟大的设计。除非有明显的理由不这样做,否则您应该修改用于显示和/或加载的代码,以便在加载/查看数据子集时进行搜索和替换。您不太可能在整个4GB数据上执行许多操作,因此将搜索和替换操作限制在您实际使用的操作范围内。此外,您的计时仍然非常不精确,因为您不知道正在处理的文件有多大

最后一点,您注意到:

加速必须是算法上的,不能链接数百万个sed调用

但是您指出您正在处理的数据是“单个大文本(~4GB)”,因此如果我正确理解您的意思,就不应该涉及任何更改

更新: 下面您指出在~4KB文件上执行操作(我假设)需要90秒,这对我来说似乎很奇怪-sed操作通常不会达到这一点。如果文件实际上是4MB(我希望如此),那么需要24小时来评估(不理想,但可能可以接受?)

它们通常只用于搜索字符串,而不用于替换字符串

太好了,这正是你需要的。在4G文本中使用无效的算法进行搜索已经够糟糕的了,但进行几次替换可能更糟糕。。。您可能需要移动千兆字节的文本,以便为源文本和目标文本的大小差异造成的扩展/收缩腾出空间

只需找到位置,然后将零件与替换零件连接起来

因此,一个愚蠢的类比是
“u.join”(“abc.split”(“)”)
,但您当然不想像
split
那样创建副本


注意:有什么理由在python中这样做吗?

可能有比这更好的方法:

re.sub('|'.join(replacements), lambda match: replacements[match.group()], text)

这是一个搜索过程,但它不是一个非常有效的搜索。这个模块可能会大大加快速度。

我也有这个用例,我需要在维基百科全文上进行大约100000次搜索和替换操作。使用
sed
awk
perl
将花费数年时间。我无法找到任何执行搜索和替换的Aho Corasick实现,因此我编写了自己的:。该工具恰好是用Python编写的(因此,如果您愿意,可以对代码进行黑客攻击),但它打包为一个像
sed
一样运行的命令行实用程序

您可以通过以下方式获得:

pip install fsed

你能展示一下你正在使用的等效正则表达式,可能还有一些计时吗?一旦你找到了所有与类似于Aho Corasick的匹配项,你就可以执行替换(当然要检查重叠),每个text.replace()调用的计时大约为60秒,这对于一百万个调用来说大约需要两年时间@Jonclements对于Aho Corasick,搜索速度很快,但我想替换人员会让你望而却步。替换字符串的长度不一定与匹配字符串的长度相同,这意味着必须批量复制大小大致相同的整个新字符串,或者至少在每次匹配之前和之后拆分为多个片段。不管怎样,这在Python中都非常慢。如果您使用C语言,则可能不是这种情况,在C语言中可以避免字符串拆分、连接等@cmd@Chrispython字符串构建中的一些内容会下降到C。比如
str.join
它不必是Python语言;而现成的工具将是理想的,因为它是我正在做的一次性操作。正如您所指出的,问题不仅在于搜索,而且因为字符串拆分,替换的成本也很高。这应该让它变得更快:1)记录位置,不要拆分2)加入,不要替换3)如果您的操作系统支持,您可以使用
发送文件
,在这种情况下,您甚至不必存储原始内容。+)对不起,不,我不知道任何现成的软件可以很快做到这一点。快速编写应用程序:当然。。。执行:不……这并没有真正的帮助;关键是我有很多,多个替代品。此解决方案将涉及约100万次对sed的调用,以及约100万次通过4GB文件的传输。上面的sed和naive实现都是
O(n*m)
,这对于给定的数据大小来说太慢了。是的
time sed's/Amistad/Amistad/g'full\u 03\u wikipedia\u news\u big>/dev/null
在90年代运行。这意味着~1million*90s=2.8年。如果操作在4KB文件上花费90s(我估计是4KB,你说的是*1million~4GB)-这些文件肯定在你的文件系统上吗?还可以使用
sed-i
进行测试