我有一个大文件,大部分都是用空格分隔的数据,我想将其解析为哈希。问题是这是主要是用空格分隔的,因此简单的string.split
将无法正常工作。
这是文件中其中一行的简化示例:
field0 field1 [ [field2a] [field2b] ] field3
外括号(包括外括号)中包含的内容必须是哈希成员。
我编写了以下函数,该函数可以运行,但是非常慢:
# row = String to be split
# fields = Integer indicating expected number of fields
def mysplit (row, fields)
# Variable to keep track of brackets
b = 0
# Variable to keep track of iterations for array index
i = 0
rowsplit = Array.new(fields)
rowsplit[0] = ""
row.each_char do |byte|
case byte
when ' '
if b == 0
i += 1
rowsplit[i] = ""
else
rowsplit[i] += byte
end
when '['
b += 1
rowsplit[i] += byte
when ']'
b -= 1
rowsplit[i] += byte
else
rowsplit[i] += byte
end
end
if i != fields - 1
raise StandardError,
"Resulting fields do not match expected fields: #{rowsplit}",
caller
elsif b != 0
raise StandardError, "Bracket never closed.", caller
else
return rowsplit
end
end
在长度为6600行的7 MB文件上运行此文件需要36秒。 值得一提的是,我的环境正在运行Ruby 1.8.7,我无法控制它。
是否可以加快速度?
答案 0 :(得分:0)
您想要.squeeze
和.strip
str = " field0 field1 [ [field2a] [field2b] ] field3"
puts str.squeeze.strip
#=> "field0 field1 [ [field2a] [field2b] ] field3"
压缩会将任何多余的空白压缩到仅1。 Strip将删除行的开头和结尾空间。
从那里开始,您应该可以使用正则表达式模式匹配将每一行解析为您要创建的数据结构,但是如果不知道如何解析数据,我将无济于事。
您还应该尽早提高期望,而无需遍历整个文件。
如果您知道自己所在的行将与您的示例中的该模式匹配:
if str.squeeze!.strip! !str[/\w+\ +\[\ +\[+\w+\]\ \[+\w+\]\ \]\ \w+/]
raise StandardError, "Raise this string pattern is wrong #{str}"
end
如果你很好,那么你可以分裂或其他:
str.split(' ')
#=>["field0", "field1", "[", "[field2a]", "[field2b]", "]", "field3"]
答案 1 :(得分:0)
要真正调整代码,可以使用基准测试模块来查找瓶颈。
但是我希望您的代码最大的问题是添加字符串:
rowsplit[i] += byte
红宝石解释器将其翻译为
rowsplit[i] = rowsplit[i] + byte
这将为输入文件中的每个字节创建一个新的字符串对象。因此,一个7MB的文件会创建并销毁700万个字符串对象。 通过使用字符串串联方法,您可能会足够快:
rowsplit[i] << byte
请注意,<<
会更改原始对象,这在您的程序中不是问题,但是在其他上下文中使用它时可能会有问题。