I want to split a string by 3 but with minimum length of 2.
This is I I got so far.
def split_string(s)
if(s.length % 3 == 1)
s.slice(0, s.length-4).scan(/.{3}/).join(' ') ' ' s[s.length-4, s.length].scan(/.{2}/).join(' ')
else
s.scan(/.{1,3}/).join(' ')
end
end
puts split_string("abcdefgh")
# abc def gh
puts split_string("abcdefghij")
# abc def gh ij
It actually works but I believe there must be more elegant solution than this
CodePudding user response:
You could use Enumerable#each_slice and then correct the result if the last string formed has only a single character.
def doit(str)
case str.size
when 0
[]
when 1
nil
else
str.each_char.each_slice(3).to_a.tap do |arr|
arr[-1].unshift(arr[-2].pop) if arr[-1].size == 1
end.map(&:join)
end
end
test = %w| abcdef abcde abcd abc ab a | << ''
#=> ["abcdef", "abcde", "abcd", "abc", "ab", "a", ""]
test.each { |s| puts "'%s' -> %s" % [s, doit(s)] }
'abcdef' -> ["abc", "def"]
'abcde' -> ["abc", "de"]
'abcd' -> ["ab", "cd"]
'abc' -> ["abc"]
'ab' -> ["ab"]
'a' ->
'' -> []
Note that doit('a') #=> nil
.
Another way would be to use recursion.
def doit(str)
case str.size
when 0
[]
when 1
nil
else
recurse(str)
end
end
def recurse(str)
case str.size
when 2,3
[str]
when 4
[str[0,2], str[2,2]]
else
[str[0,3]] recurse(str[3..-1])
end
end
test.each { |s| puts "'%s' -> %s" % [s, doit(s)] }
displays the same results as above.