String#separate です。分割のすべての場合を尽くします。配列で返します。
class String def separate(n) return [[self]] if n <= 1 or n > self.length if n == 2 st = self return [[st]] if st.length == 1 ar = [] (st.length - 1).times {|i| ar << [st[0..i], st[i + 1..-1]]} ar else seprt([[self]], n) end end private def seprt(ar, n) if n == 2 a = [] ar.each do |ar1| b = ar1.dup ar1.each_with_index do |st, j| next if st.length == 1 st.separate(2).each do |ar2| c = b.dup c[j] = ar2 c.flatten! a << c end end end a.uniq else (n - 1).times {ar = seprt(ar, 2)} ar end end end
実行例。
p "12345678".separate(3) =begin [["1", "2", "345678"], ["1", "23", "45678"], ["1", "234", "5678"], ["1", "2345", "678"], ["1", "23456", "78"], ["1", "234567", "8"], ["12", "3", "45678"], ["12", "34", "5678"], ["12", "345", "678"], ["12", "3456", "78"], ["12", "34567", "8"], ["123", "4", "5678"], ["123", "45", "678"], ["123", "456", "78"], ["123", "4567", "8"], ["1234", "5", "678"], ["1234", "56", "78"], ["1234", "567", "8"], ["12345", "6", "78"], ["12345", "67", "8"], ["123456", "7", "8"]] =end
追記
ブロックがある場合はそれを実行、ない場合は Enumerator を返すようにしました。(2016/3/6)
class String def separate(n) ar = seprt2(n) if block_given? ar.each {|x| yield(x)} else ar.to_enum end end def seprt2(n) return [[self]] if n <= 1 or n > self.length if n == 2 st = self return [[st]] if st.length == 1 ar = [] (st.length - 1).times {|i| ar << [st[0..i], st[i + 1..-1]]} ar else seprt([[self]], n) end end private :seprt2 end p "12345678".separate(3).to_a p "abcdefgh".separate(4) {|ar| print "#{ar[0].upcase}, "}; puts
再追記
ここで実装した Array#divide を使えば、こんな具合になります。(2018/2/10)
class String def divide(n) e = chars.divide(n).with_object([]) {|i, ar| ar << i.map(&:join)}.to_enum block_given? ? loop {yield(e.next)} : e end end