時代遅れひとりFizzBuzz祭り GNU AWK編

時代遅れひとりFizzBuzz祭り、今回はGNU AWK。前回がC++だったので、その流れでJava……ではなく、よく使う言語繋がりでgawkにしてみた。

gawkは、まだ私がC言語ぐらいしか使えなかった頃に、ちょっとしたツール自作用に使い始めた言語だ。既にPerl 5.8.8の頃だったけど、何故か「Perlの前にsedawkだ」と考えてgawkを選択したのだった。

gawkは行指向のテキストデータを処理するのに向いている。今でもgawkワンライナーする機会は多い。しかし、もうちょっと本格的なツールを書きたい場合、別の言語*1を使った方が楽だ。

それでも世間ではPerlが出てくる以前には大規模なプログラミングでnawkを使用することもあった訳で、実はコンパクトながらもそれなりに機能が揃っている。更にgawkだとTCP通信やビット演算その他色々と拡張されていたりする。

私は『プログラミング言語AWK』を片手にAWKのコードを書く人なので、nawk相当の機能でFizzBuzzを書いてみた。

#!/usr/bin/gawk -f

function fizzbuzz(n,    str)
{
	if (n % 3 == 0)
		str = "Fizz"
	if (n % 5 == 0)
		str = str "Buzz"

	return length(str) == 0 ? n : str
}

BEGIN {
	for (i = 1; i <= 100; ++i) {
		print fizzbuzz(i)
	}
}

このスクリプトは、入力データが無くても動作する。

seq等を使用して外部から行指向で数値を入力する場合は、次のようなコードになる。

#!/usr/bin/gawk -f

function fizzbuzz(n,    str)
{
	if (n % 3 == 0)
		str = "Fizz"
	if (n % 5 == 0)
		str = str "Buzz"

	return str == "" ? n : str
}

{
	print fizzbuzz($0)
}

但し、外部から入力されたデータを何も検証していないので妙なことになる。Windows上でgawk 3.1.6で試してみたところ、「a」と入力するとFizzBuzzと表示されてしまった。

そこで正規表現で簡単な入力制限をしてみた。1以上の整数値(10進数表現のみ)ならOKで、それ以外の入力はエラーとしているつもり。

#!/usr/bin/gawk -f

function fizzbuzz(n,    str)
{
	if (n % 3 == 0)
		str = "Fizz"
	if (n % 5 == 0)
		str = str "Buzz"

	return str == "" ? n : str
}

/^[ \t]*[1-9][0-9]*[ \t]*$/ {
	print fizzbuzz($0)
	next
}

{
	print "Invalid input:\"" $0 "\""
}

但しこれでも整数値として扱える最大値についてのケアをしていないので、あまり大きな値を入力されると妙なことになるかもしれない。

2011/06/05追記

そういえば、エラーメッセージは標準エラーに出力するべきだった。

#!/usr/bin/gawk -f

function fizzbuzz(n,    str)
{
	if (n % 3 == 0)
		str = "Fizz"
	if (n % 5 == 0)
		str = str "Buzz"

	return str == "" ? n : str
}

/^[ \t]*[1-9][0-9]*[ \t]*$/ {
	print fizzbuzz($0)
	next
}

{
	print "Invalid input: \"" $0 "\"" > "/dev/stderr"
}

これで一安心。

*1:例えばPerlとかPythonとかRubyとか。