Fill in the blanks

Fill in the blanks 終了。
awkの戦いは結構しんどかった。
始め 34B で並んでから、33B、32B と後追いになってしまったし、追いつくのが大変だった。
34B は

RS="_"{ORS=substr(S=S$0FS,i,1)}i++

これでも、結構難しかったし、これ以上縮まるとは思いもよらなかった。この解は、考え方は割と面白い。awk の行区切り文字(RS: Record Separator)として、'_' をを指定し、出力行区切り文字(ORS)を入力の先頭行の文字を順に割り当てることで、問題の 'fill in' を実現するというもの。$0 の後ろに1文字 FS にて空白文字を入れているのは、最終レコードの後ろにつく ORS を空白にするため。
33B は、

RS="_"{ORS=substr(S=S$NR,i,1)}i++

$0 の代わりに $NR とすることで、$2、$3、、、と参照することになるが、それらは、空なので、最終レコードの後ろにつく ORS を空白にすることができる。
32Bは、

ORS=substr(S=S$0FS,i++,0<RS="_")

ちょっとした式変形。でもなかなか思いつけなかった。$NR を $0FS に戻したのは、$NR だと ORS が空になってしまい、式の値は、false と判断され、最終レコードが出力されないため。

★☆★☆★☆★☆

fill dots@awk

◇◆◇ 以下 Spoiler注意 ◇◆◇
少し前の endless 問題。
ちょっと考えてたら、awk で、26B と短い解ができた。この問題、'*' に囲まれた空白をドット '.' で置き換えるという問題。当初は、

{for(;sub(/\* /,"*.")+sub(/\. /,"..");)}1

こんな解で、41B。わりとすなおな解だ。この問題、mawk 独特の behavior を使うと短くなる。150. duplicate certain lines _C_で使った方法だ。つまり、gsub に正規表現として、/^ で始まる行の先頭からの指定を指定したものを使うもの。gsub と '/^' と少し矛盾した組み合わせのようだが、mawk では、この組み合わせは面白い動きをする。たとえば、行の先頭から続く 'A' を 'B' に置換するという問題を考えると、

AAAAAAAAxxAAxx
    ↓
BBBBBBBBxxAAxx

つまり、このような置換を考えた場合、通常の awk では、やりにくいが、mawk では、

gsub(/^A/,"B")

でできてしまう。もし、awk正規表現に back reference があれば、

{for(;sub(/(^|B)A/,"\1B");)}

とでもするところだが、back reference が無いため、上のようなやり方が有用だ。因みに、行末から逆方向にやることはできないようだ。

gsub(/A$/,"B")

これは、期待通りには動かない。
さて、fill dots に戻ると、まず、全空白を一気に "." に置き換えてやる。その後、先頭から始まる "."* を上記の方法で、空白に戻すということをやると、以下、26B になる。

gsub(FS,".")gsub(/^\./,FS)