我一直在寻找一种优雅而有效的方法,将字符串块化为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)
=> []
您可能希望chunk("", n)
返回[""]
而不是[]
。如果是这样,只需将其添加为方法的第一行:
return [""] if string.empty?
您会推荐更好的解决方案吗?
修改
感谢Jeremy Ruten这个优雅而有效的解决方案:
def chunk(string, size)
string.scan(/.{1,#{size}}/)
end
答案 0 :(得分:148)
使用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"]
答案 1 :(得分:17)
这是另一种方法:
"abcdefghijklmnopqrstuvwxyz".chars.to_a.each_slice(3).to_a.map {|s| s.to_s }
=> [“abc”,“def”,“ghi”,“jkl”,“mno”,“pqr”,“stu”,“vwx”,“yz”]
答案 2 :(得分:5)
我认为如果你知道你的字符串是块大小的倍数
,这是最有效的解决方案def chunk(string, size)
(string.length / size).times.collect { |i| string[i * size, size] }
end
和部分
def parts(string, count)
size = string.length / count
count.times.collect { |i| string[i * size, size] }
end
答案 3 :(得分:2)
我做了一点测试,将约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
答案 4 :(得分:1)
test.split(/(...)/).reject {|v| v.empty?}
拒绝是必要的,因为否则包括集合之间的空白区域。我的正则表达式并没有完全看到如何解决这个问题。
答案 5 :(得分:1)
这是另一种解决情况稍有不同的解决方案,当处理大型字符串时,无需一次存储所有块。这样,它可以一次存储单个块,并且比切片字符串快得多:
io = StringIO.new(string)
until io.eof?
chunk = io.read(chunk_size)
do_something(chunk)
end
答案 6 :(得分:1)
一种更好的解决方案,考虑了字符串的最后一部分,该部分可能小于块大小:
def chunk(inStr, sz)
return [inStr] if inStr.length < sz
m = inStr.length % sz # this is the last part of the string
partial = (inStr.length / sz).times.collect { |i| inStr[i * sz, sz] }
partial << inStr[-m..-1] if (m % sz != 0) # add the last part
partial
end
答案 7 :(得分:0)
只需text.scan(/.{1,4}/m)
就可以解决问题
答案 8 :(得分:-1)
您还有其他一些限制因素吗?否则我会非常想做一些简单的事情,比如
[0..10].each {
str[(i*w),w]
}