在Ruby中解析一个大字符串

时间:2014-11-11 03:02:50

标签: ruby regex parsing ruby-2.0

我有一个包含字符串的几百兆字节的文件:

str1 x1 x2\n
str2 xx1 xx2\n
str3 xxx1 xxx2\n
str4 xxxx1 xxxx2\n
str5 xxxxx1 xxxxx2

其中x1x2是一些数字。数字x(...x)1x(...x)2的大小有多大是未知的。

每一行都在"\n"中。我有一个字符串列表str2str4

我想找到这些字符串的相应数字。

我正在做的事情非常简单(并且可能在性能方面效率不高):

source_str = read_from_file() # source_str contains all file content of a few hundred Megabyte
str_to_find = [str2, str4]
res = []
str_to_find.each do |x|
  index = source_str.index(x)
  if index
    a = source_str[index .. index + x.length] # a contains "str2"

    #?? how do I "select" xx1 and xx2 ??


    # and finally...
    # res << num1
    # res << num2
  end
end

请注意,由于错误source_str.split("\n"),我无法应用ArgumentError: invalid byte sequence in UTF-8,我无法通过任何方式更改文件来解决此问题。 文件无法更改

2 个答案:

答案 0 :(得分:3)

您希望避免在内存中读取数百兆字节,以及重复扫描它们。这有可能永远占用,同时堵塞机器的可用内存。

尝试重新解决问题,因此您可以将大输入文件视为,因此不要求您要查找的每个字符串“它是否存在于我的文件中?” ,尝试询问文件中的每一行“它包含我正在寻找的字符串吗?”。

str_to_find = [str2, str4]
numbers = []
File.foreach('foo.txt') do |li|
  columns = li.split
  numbers += columns[2] if str_to_find.include?(columns.shift)
end

另外,请再次阅读@ theTinMan关于文件编码的答案 - 他建议您可以微调文件的读取以避免错误,而无需更改文件本身

如果您在str_to_find中有大量商品,我建议您使用Set代替Array以获得更好的效果:

str_to_find = [str1, str2, ... str5000].to_set

答案 1 :(得分:2)

如果你想在文本文件中找到一条听起来像你正在阅读的行,那么请逐行阅读该文件。

IO类具有foreach方法,这使得逐行读取文件变得容易,这也可以轻松找到包含您要查找的特定字符串的行。

如果您将源输入文件保存为“foo.txt”,则可以使用以下内容读取它:

str2 = 'some value'
str4 = 'some other value'
numbers = []
File.foreach('foo.txt') do |li|
  numbers << li.split[2] if li[str2] || li[str2]
end

在循环结束时numbers应包含您想要的数字。

你说你得到了一个编码错误,但是你没有告诉我们造成它的字符是什么。没有这些信息我们无法真正帮助您解决这个问题,除非您需要告诉Ruby文件编码是什么。你可以在打开文件时这样做;您可以将open_args正确设置为编码应该是什么。赔率很高它应该是ISO-8859-1或Win-1252的编码,因为它们在Windows机器中很常见。


  

我必须找到一个值列表,遍历每一行似乎不合理,因为我必须反复迭代每个值。

我们只能使用您提供给我们的示例。由于在你的问题中没有明确解释,你得到的答案基于最初的说法。

Ruby的Regexp拥有使这项工作成为必需的工具,但要正确地完成它需要利用Perl的Regexp :: Assemble库,因为Ruby没有任何接近它。有关详细信息,请参阅“Is there an efficient way to perform hundreds of text substitutions in ruby?”。

请注意,此允许您扫描内存中的大字符串,但这仍然不是处理您所谈论内容的好方法。我会使用数据库来代替这种任务。