Ruby自定义拆分功能缓慢

时间:2018-10-22 19:04:17

标签: ruby string performance split ruby-1.8.7

我有一个大文件,大部分都是用空格分隔的数据,我想将其解析为哈希。问题是这是主要是用空格分隔的,因此简单的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,我无法控制它。

是否可以加快速度?

2 个答案:

答案 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

请注意,<<会更改原始对象,这在您的程序中不是问题,但是在其他上下文中使用它时可能会有问题。