我有一个包含字符串的几百兆字节的文件:
str1 x1 x2\n
str2 xx1 xx2\n
str3 xxx1 xxx2\n
str4 xxxx1 xxxx2\n
str5 xxxxx1 xxxxx2
其中x1
和x2
是一些数字。数字x(...x)1
和x(...x)2
的大小有多大是未知的。
每一行都在"\n"
中。我有一个字符串列表str2
和str4
。
我想找到这些字符串的相应数字。
我正在做的事情非常简单(并且可能在性能方面效率不高):
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
,我无法通过任何方式更改文件来解决此问题。 文件无法更改
答案 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?”。
请注意,此将允许您扫描内存中的大字符串,但这仍然不是处理您所谈论内容的好方法。我会使用数据库来代替这种任务。