在Ruby中将字符串切割成给定长度的块的最佳方法是什么?

Min*_*ark 85 ruby string chunking

我一直在寻找一种优雅而有效的方法,将一个字符串块化为Ruby中给定长度的子字符串.

到目前为止,我能想到的最好的是:

def chunk(string, size)
  (0..(string.length-1)/size).map{|i|string[i*size,size]}
end

>> chunk("abcdef",3)
=> ["abc", "def"]
>> chunk("abcde",3)
=> ["abc", "de"]
>> chunk("abc",3)
=> ["abc"]
>> chunk("ab",3)
=> ["ab"]
>> chunk("",3)
=> []
Run Code Online (Sandbox Code Playgroud)

您可能想要chunk("", n)返回[""]而不是[].如果是这样,只需将其添加为方法的第一行:

return [""] if string.empty?
Run Code Online (Sandbox Code Playgroud)

你会推荐更好的解决方案吗?

编辑

感谢Jeremy Ruten提供的优雅高效的解决方案:

def chunk(string, size)
    string.scan(/.{1,#{size}}/)
end
Run Code Online (Sandbox Code Playgroud)

Jer*_*ten 152

用途String#scan:

>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{4}/)
=> ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx"]
>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{1,4}/)
=> ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx", "yz"]
>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{1,3}/)
=> ["abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz"]
Run Code Online (Sandbox Code Playgroud)

  • 小心这个解决方案; 这是一个正则表达式,它的`/ .`位意味着它将包括所有字符,除了换行符`\n`.如果要包含换行符,请使用`string.scan(/.{4}/m)` (17认同)
  • def chunk(字符串,大小); string.scan(/ {1,#{大小}} /.); 结束 (3认同)

Jas*_*son 17

这是另一种方法:

"abcdefghijklmnopqrstuvwxyz".chars.to_a.each_slice(3).to_a.map {|s| s.to_s }
Run Code Online (Sandbox Code Playgroud)

=> ["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]

  • 或者:`"abcdefghijklmnopqrstuvwxyz".chars.each_slice(3).map(&:join)` (14认同)
  • 我喜欢这个,因为它适用于包含换行符的字符串. (3认同)

dav*_*puh 6

我认为如果你知道你的字符串是块大小的倍数,这是最有效的解决方案

def chunk(string, size)
    (string.length / size).times.collect { |i| string[i * size, size] }
end
Run Code Online (Sandbox Code Playgroud)

和零件

def parts(string, count)
    size = string.length / count
    count.times.collect { |i| string[i * size, size] }
end
Run Code Online (Sandbox Code Playgroud)

  • 如果用`(string.length + size - 1)/ size`替换`string.length/size`,你的字符串不必是块大小的倍数 - 这种模式在C代码中很常见,必须处理整数截断. (3认同)

prc*_*rcu 6

这是针对稍微不同的情况的另一种解决方案,在处理大字符串时并且不需要一次存储所有块。通过这种方式,它一次存储单个块,并且执行速度比切片字符串快得多:

io = StringIO.new(string)
until io.eof?
  chunk = io.read(chunk_size)
  do_something(chunk)
end
Run Code Online (Sandbox Code Playgroud)


小智 6

我做了一个小测试,将大约 593MB 的数据切成 18991 个 32KB 的块。在我按下 ctrl+C 之前,您的 slice+map 版本使用 100% CPU 运行了至少 15 分钟。这个版本使用 String#unpack 在 3.6 秒内完成:

def chunk(string, size)
  string.unpack("a#{size}" * (string.size/size.to_f).ceil)
end
Run Code Online (Sandbox Code Playgroud)