如何在Ruby中高效地迭代和更新大型字符串?

3

我有一个6GB大小的文本文件。我想要做类似于以下的操作:

str.gsub!('xxx', 'x')

这个想法是使用seek读取1MB的块。有没有更有效率的方法来替换上述内容?也许可以使用类似C语言数组访问的方式来迭代字符串?


1
它有行吗?你想将文件写回吗? - Eric Duminil
1
一个选择是使用mmap(不幸的是这需要第三方gem)。如果你决定使用块,则需要记住你还需要处理跨越它们边界的模式,即如果前两个x在第一个块的末尾,而第三个x在随后块的开头。 - Greg Navis
1
你想要 'xxxx'.sub('xxx', 'x') #=> => 'xx' 吗? - Cary Swoveland
1
你仍然无法直接在原文件中进行添加或删除字符的修改。你需要创建一个新文件来输出修改后的内容。插入或删除字符的过程是比较耗费时间的,而且随着需要在字符串缓冲区中左右移动的字符数量增加,成本也会增加。 - tadman
1
seek会定位文件中的位置,但这并不能解决问题。文本文件是一种顺序文件,这意味着它必须按顺序读取和写入,你无法跳到一个位置并写入任意数量的字符,让文件自动扩展或收缩。操作系统、磁盘和文件并不是这样工作的。 - the Tin Man
显示剩余8条评论
2个回答

3

您可以使用子进程和 sed 来实现,这将非常快:

`sed -i -E 's:xxx:x:g' file_name`

Ruby 的逐行读取速度很快,但这会更快,因为 sed 是为此目的编写的。 - the Tin Man

2
如果巨大的文件有超过20行,您可以使用以下方式:
File.open('new_file', 'w') do |out|
  File.foreach('huge_file.txt') do |line|
    out.puts line.gsub('xxx', 'x')
  end
end

这将占用非常少的内存,并且应该相当快。

如果这个6GB的文件只有两行呢? :-) - Cary Swoveland
@CarySwoveland:没错。已更新。 - Eric Duminil
1
@EricDuminil 这个文件有数百万行。 - B Seven
1
如果代码有数百万行,那么在纯Ruby中逐行阅读并在每行上使用gsub是最快的方法。您不能使用块读取,因为您可能会在块的末尾得到xx,并错过了它实际上是xxx的事实,因为下一个块以x开头。使用sed会更快,只要子shell的生成速度不会消耗掉这个好处。 - the Tin Man

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接