LL Golf Hole 2 - 文字列に含まれる単語の最初の文字を大文字にする

文字列操作に特化した言語と言われる awk ですが、意外にもこうした問題は得意とは言えません。 それは正規表現が四大言語と比較して弱いことや、gawk 以外では後方参照も使えないことが大きく影響していると思います。

ここではオーソドックスな解答を用意してみました。

{
    for (i = 1; i <= NF; i++) {
        sub(/./, toupper(substr($i, 1, 1)), $i);
    }
}
{
    print $0;
}

もちろん while ループでも記述することができます。

{
    while (++i <= NF) {
        sub(/./, toupper(substr($i, 1, 1)), $i);
    }
}
1

実際に実行してみると以下のようになります。

$ echo 'LL day and night' | gawk -f doukaku_capitalize.awk
LL Day And Night

予期している答えが出るのは当然として、これでは Golf になりません。 あのeban さんも参戦してくださっていますので、awk の凄い解答がみられるのではないかと思いますが、少し変わった解答を用意してみました。

$ echo 'LL day and night' | \
gawk -v RS=" " -v ORS=" " -v FS="" -v OFS="" '$1=toupper($1)'
LL Day And Night
$ echo 'LL day and night' | \
gawk -v RS=" " -v ORS=" " 'sub(substr($0,1,1),toupper(substr($0,1,1)))'
LL Day And Night
$ echo 'LL day and night' | \
gawk -v RS=" " -v ORS=" " 'sub(/./,toupper(substr($0,1,1)))'
LL Day And Night

つまり、awk で単語をフィールドとして扱おうとすると for 文などのループを用いて走査する必要がありますが、レコードとして扱うようにしてしまえば走査する必要はなくなります。 また、単語の最初の文字は substr($0, 1, 1) なのですが、これも全ての文字を単語に分解することで扱いが簡単になります。(最初の例)

また、全てパターン部分しかなくアクションがないため不思議に思うかもしれませんが、パターン部分は評価式ですから、0 よりも大きな数を返すようなものを用いれば良い分けです。 最初の例は代入ですから常に真ですし、後の 2 つの例は sub() 関数ですから置換が成功すれば常に真になります。

tag_nawk.pngtag_nawk.pngtag_nawk.pngtag_nawk.png