質問: 0〜9やa〜zの配列の要素から3個を選んだときの重複順列を数え上げたければ、 ``` p ('000'..'999').to_a p ('aaa'..'zzz').to_a ``` ですみます。 平仮名で同様のことをしようと ``` # -*- coding: cp932 -*- p ('あああ'..'んんん').to_a ``` とするとパソコンが止まりました。(**上記コードは実行しないでください。**) なぜ上手くいかないか知ろうと、 ``` # -*- coding: cp932 -*- p ('ああ'..'んん').to_a ``` を実行すると、 重複順列に「あ〜ん以外の別の文字が混ざっている」ことがわかりました。 なぜ、「あ〜ん以外の別の文字が混ざる」か教えてください。
回答: 調べてみました。 `('ああ'..'んん').to_a` では Range#each が呼ばれるので、2 つめ以降の要素は `String#succ` で生成されます。 たとえば `'aa'.succ` は `'ab'` に `'az'.succ` は `'ba'` になるので、最初に挙げられた例は期待通り動作します。 ただしこれは、英数字の場合で、String#succ のドキュメント を見てみると、下記の記述があります。 > > アルファベットや数字をまったく含まない場合は、 単純に文字コードを 1 増やします。 > > > このため "あん" の次が "いあ" などにはならず、カタカナや漢字など、文字コード表で "ん" より後にある文字も含むことになります。 期待する結果を得るには、例えば、配列の組み合わせを得る `Array#permutation` を使って次のように書く事ができます。 ``` ('ぁ'..'ん').to_a.permutation(3){|chars| p chars.join } ``` なお、エンコーディングが UTF-8 だと、`"ん".succ.succ.succ.succ` が `"ぁぁ"` になり、英数字に似た挙動になりました。ご参考まで。