character subsets in anagol

生きてます。
あんまり人気はない問題でしたがおもしろいコードだったので少しだけ紹介。正規表現の気持ち悪さが際立ってる感じがとてもいい。
まずは ksk さんのコード。43B。

$><<[p].product(*gets.scan(/()(.)/)|[[$/]])

配列の組み合わせを列挙する関数 product を使っているのですが、引数が面白い。
uniq の代わりと要素の追加に 「|」 を使うのは基本として「scan(/()(.)/)」が気持ち悪くていい。この発想はなかった。

irb(main):011:0> p [p].product(*"123\n".scan(/()(.)/)|[[*$/]])
[[nil, "", "", "", "\n"],
 [nil, "", "", "3", "\n"],
 [nil, "", "2", "", "\n"],
 [nil, "", "2", "3", "\n"],
 [nil, "1", "", "", "\n"],
 [nil, "1", "", "3", "\n"],
 [nil, "1", "2", "", "\n"],
 [nil, "1", "2", "3", "\n"]]

すごく綺麗。というか product とか知らなかった。これ使ったらめちゃくちゃ簡単じゃないか…
で、次は自分のコード。42B。

s=$/;gets;s+=[p,*s]*$1while/(.)#$1+/;$><<s

ぱっと見では何やってるかあんまり分からないと思います。
while の条件になっている正規表現は「一回目は文字列全体にヒットし、二回目から $1 の前の文字にヒットする」ようになってます。
一回目は $1 は nil なので正規表現は /(.)+/ と解釈されます。これ不思議なんですが $1 には最後の文字が入るんですよね。
二回目以降は前回ヒットした文字の一つ前の文字にヒットします。素晴らしー。
文字列を作る部分は、まあ勘で読んでください。おしまい。