2013-10-16 96 views
4

如果我有一個像下面這樣的字符串,我會如何在每個第三個字符或任何其他指定的字符處分割它?如何在Ruby中對某個字符進行分片或分割字符串?

b = "123456789" 

,結果會是這樣:

b = ["123","456","789"] 

我一直使用這些方法的嘗試:b.split("").each_slice(3).to_a

但它會導致這樣的:[["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]]

謝謝您的幫助!

回答

5

你幾乎做到了。

b = "123456789" 
b.split("").each_slice(3).map(&:join) # => ["123", "456", "789"] 
6
b = "123456789" 
b.chars.each_slice(3).map(&:join) 
# => ["123", "456", "789"] 
6

我會使用:

b = "123456789" 
b.scan(/.{3}/) # => ["123", "456", "789"] 

如果OP的樣品都將在不同的長度,或者它有一個嵌入 「\ n」,一個簡單的改造工程:

b = "123456789" 
b.scan(/.{1,3}/) # => ["123", "456", "789"] 
b[0..-2].scan(/.{1,3}/) # => ["123", "456", "78"] 
"#{ b }\n#{ b }".scan(/.{1,3}/) # => ["123", "456", "789", "123", "456", "789"] 

現在,如果在偶數的「3」邊界上存在嵌入的「\ n」NOT,它遊:

"#{ b[0..-2] }\n#{ b }".scan(/.{1,3}/) # => ["123", "456", "78", "123", "456", "789"] 

但越來越相當遙遠從OP的簡單的規範,並且可以通過剝離新線(S)固定第一:

"#{ b[0..-2] }\n#{ b }".delete("\n").scan(/.{1,3}/) # => ["123", "456", "781", "234", "567", "89"] 
+0

權。如果我正確理解要求,這是一個更好的答案 –

+2

+1漂亮和優雅。如果'b.length%3!= 0'不起作用,但是這樣做:'b.scan(/..?.?/)' – iamnotmaynard

+1

如果你有''\ n「'串。 – detunized

2

這不會創建臨時數組,適用於任何集合和數量的字符,不使用慢速正則表達式。雖然沒有那麼優雅。

s = "1234567" 
(0...s.size/3).map { |i| s[i * 3, 3] } 
# => ["123", "456", "7"] 

基準:

require "benchmark" 

N = 100000 

Benchmark.bm do |x| 
    b = "123456789" 
    x.report { N.times { (0...b.size/3).map { |i| b[i * 3, 3] } } } 
    x.report { N.times { b.scan(/.{3}/) } } 
    x.report { N.times { b.chars.each_slice(3).map(&:join) } } 
    x.report { N.times { b.split("").each_slice(3).map(&:join) } } 
end 

結果:

$ ruby split3.rb 
     user  system  total  real 
    0.080000 0.000000 0.080000 ( 0.079944) 
    0.130000 0.000000 0.130000 ( 0.127715) 
    0.300000 0.000000 0.300000 ( 0.299186) 
    0.640000 0.000000 0.640000 ( 0.641817) 

我試圖改變行的順序,看看是否有任何奇怪的副作用。結果是一致的。訂單無關緊要。

+0

如果只有某人對所有這些答案進行基準測試...... :) –

+0

我對它進行了基準測試。 – detunized

+0

's =「12 \ n3456 \ n7」; (0 ... s.size/3).map {| i | s [i * 3,3]}#=> [「12 \ n」,「345」,「6 \ n7」]'。 –

2

除了其他答案,如果你想分裂一個任意的字符集(這個答案不包括每個第三個字符,因爲已經有足夠多的答案),並決定其中分裂字符去,你也可以使用split像這樣:

# Split and include splitting character in next slice 
"123456789".split(/(?=[36])/)  # => ["12", "345", "6789"] 

# Split and include splitting character in slice 
"123456789".split(/(?<=[36])/) # => ["123", "456", "789"] 

# Split and exclude character from slices 
"123456789".split(/[36]/)   # => ["12", "45", "789"] 

記住,這確實使用正則表達式,併爲你的目的,它可能是更好的使用在尋找一種方法來分割字符串少(請參閱detunized的答案,這是相當簡潔和合理的方式來處理這個問題)。根據被拆分字符串的複雜程度,你分裂的內容,如何分割字符/短語等等,你的方法可能會改變。

5

另一種方式:

my_s, my_a = '123456789', [] 
my_a << my_s.slice!(0..2) until my_s.empty? 
p my_a # => ["123", "456", "789"] 
+2

非常好的研究.. :)我喜歡。 –

+0

不錯。可以用'shift(3)'代替'slice!(0..2)'。 –

+0

我正在使用切片!在atring上。字符串不是可枚舉的(如果我沒有記錯的話,從1.9開始)。 – hirolau