如何在Ruby中的某个字符上切割或拆分字符串?

时间:2022-09-26 21:38:04

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

如果我有一个类似下面的字符串,我将如何在每个第3个字符或任何其他指定的字符分割它?

b = "123456789"

The result would be this:

结果是这样的:

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

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

我尝试过使用这些方法:b.split(“”)。each_slice(3).to_a

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

但它导致:[[“1”,“2”,“3”],[“4”,“5”,“6”],[“7”,“8”,“9”]]

Thank you for your help!

感谢您的帮助!

6 个解决方案

#1


6  

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

#2


6  

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:

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

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

现在,如果在“3”边界上存在嵌入的“\ n”NOT,则会断开:

"#{ 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:

但是,从OP的简单规范开始,这已经相当远了,可以通过首先剥离新行来修复:

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

#3


5  

You almost made it.

你几乎成功了。

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

#4


5  

Another way:

其他方式:

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

#5


2  

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.

请记住,这确实使用了正则表达式,为了您的目的,最好找到一种方法来使用较少的过度路线来分割字符串(请参阅detunized的答案,这是相当简洁和合理的方式处理这个(事情)。根据要拆分的字符串的复杂性,拆分的内容,拆分字符/短语/等等,您的方法可能会发生变化。

#6


2  

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.

我试图改变线的顺序,看看是否有任何奇怪的副作用。结果是一致的。订单无关紧要。

#1


6  

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

#2


6  

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:

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

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

现在,如果在“3”边界上存在嵌入的“\ n”NOT,则会断开:

"#{ 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:

但是,从OP的简单规范开始,这已经相当远了,可以通过首先剥离新行来修复:

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

#3


5  

You almost made it.

你几乎成功了。

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

#4


5  

Another way:

其他方式:

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

#5


2  

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.

请记住,这确实使用了正则表达式,为了您的目的,最好找到一种方法来使用较少的过度路线来分割字符串(请参阅detunized的答案,这是相当简洁和合理的方式处理这个(事情)。根据要拆分的字符串的复杂性,拆分的内容,拆分字符/短语/等等,您的方法可能会发生变化。

#6


2  

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.

我试图改变线的顺序,看看是否有任何奇怪的副作用。结果是一致的。订单无关紧要。