简体   繁体   中英

How do you slice or split a string on a certain character in Ruby?

If I had a string like the one below how would I split it at every 3rd character or any other specified character?

b = "123456789"

The result would be this:

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

I've tried using these method: b.split("").each_slice(3).to_a

But it results in this : [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]]

Thank you for your help!

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

I'd use:

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

If the OP's sample were to be a different length, or it had an embedded "\\n", a simple modification works:

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"]

Now, if there is an embedded "\\n" NOT on an even "3" boundary, it breaks:

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

but that is getting rather far afield from the OP's simple specification, and can be fixed by stripping the new-line(s) first:

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

You almost made it.

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

Another way:

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

This doesn't create temporary array, works for any set and number of characters and doesn't use slow regular expressions. Not as elegant though.

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

Benchmark:

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

Results:

$ 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)

I tried to change the order of the lines to see if there's any strange side effects. The results are consistent. The order doesn't matter.

In addition to the other answers, if you want to split on an arbitrary set of characters (this answer doesn't cover every third character because there's more than enough answers on that already) and decide where the splitting characters go, you can also use split like so:

# 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"]

Bear in mind that this does use regular expressions and, for your purposes, it may be better to find a way to split the string using a less over-the-top route (see detunized's answer, which is fairly succinct and a reasonable way to handle this). Depending on the complexity of the string being split, what you're splitting on, what to do with splitting characters/phrases/etc., and so on, your approach might change.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM