(2010-01の一覧)
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

2010-01-06 Wed (他の年の同じ日: 2006 2007)

今更だけどFizzBuzz問題(正規表現で)
2010-01-06-1 / カテゴリ: [programming][正規表現][perl] / [permlink]

更にPerlネタ

昨日([2010-01-05-1])に引き続き他人の日記をこっそり覗き見しているとFizzBuzz問題のPerlのコードを発見
2年位前に結構盛り上がってたみたいだけど、何故かリアルタイム参戦してなかったので、ちょっとやってみた。

が、何のヒネリも入らなかった。
perl -le 'print (($_%15==0)?"FizzBuzz":($_%3==0)?"Fizz":($_%5==0)?"Buzz":$_) for (1..100)'

んで、件のエントリに
剰余を使うな

とかありました
とあったし、ワンライナーは出尽くしてるっぽいので、剰余禁止(ついでに乗除算禁止、変換テーブル禁止)で、Perl使いらしく正規表現(キャプチャ禁止)でマニアックに実装してみた。
(ググったらそのものズバリな正規表現でFizzBuzzは見つかったけど、手持ちスキルはPerl5.8止まりなのでよくわからんかったorz <- 何がPerl使いだ>自分)

#!/usr/bin/perl -l
for (1..100) {
  s/(?<=[50])$/Buzz/;
  for (($a = $_) =~ s/\D*//g; $a !~ /^.$/; $a =~ s/(\d)(\d)/$1+$2/eg){}
  s/(?=$|\D)/Fizz/ if $a =~ /[369]/;
  s/\d+(?=\D)//;
  print;
}

とりあえず解説。
処理の流れ: 5倍数時は"数字Buzz"に置換、3倍数時は"数字Fizz"に置換、最後に数字以外が付加されていれば数字を削除して出力する。先に5を処理してるのは "5か0 + (非数字があるか空)" のパターンでキャプチャ不使用で末尾にBuzzを付加するパターン置換がどうしてもできなかったからorz

  • 1行目: シェバングは -l 付き。print; 単体で手抜き出力させるため:p
  • 2-8行目: 1から100までループ
  • 3行目: 「5の倍数は1桁目が0か5」なので、末尾($)が5or0([50])の場合に、数字部分を残して((?<=))末尾のみをBuzzに置換。数字は3の倍数判定に使用するので消さない。
  • 4行目: 「3の倍数は各桁の数字の和が3で割り切れる」ので、各桁の和を求める処理を1桁になるまで繰り返して3or6or9なら3の倍数ってことで、4行目のfor()の初期処理で倍数判定処理用に一時変数に一旦コピー(これがかなり気に入らん)、ただし既に5の倍数時はBuzzが付加されているので、数字以外(\D*)はコピー後($a = $_)に消去(s///g)、継続条件式で1桁判定(length($a)!=1に置換え可)、更新式で"数数"を((\d)(\d))数+数($1+$2/e)に全部(g)置換(s///)する。
  • 5行目: 「元のループ変数($_)」を1桁になるまで求めた各桁の和($a)が3or6or9(/[369]/)だった場合のみ(if修飾子)置換。ただし5の処理で既にBuzzが付いてる場合があるので、次の文字((?=))が末尾か非数字($|\D)の位置を置換。
  • 6行目: この時点で、数字のみ or 数字+Fizz or 数字+Buzz or 数字+FizzBuzz になってるので、次の文字((?=))が非数字(\D)の数字全て(\d+)を消去(s///);
  • 7行目: 出力
てか、Perlって空処理の制御構文でもブレース省略できないのね。
Cだと
for (...);
ってできるけど。


あ、多分当時はCに毒されてPerlを忘れつつあったから、面倒がって流行に乗らなかったのかも。(2007年のprogrammingカテがCばっか…)
前の日 / 次の日 / 最新 / 2010-01

2013 : 01 02 03 04 05 06 07 08 09 10 11 12
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12

最終更新時間: 2013-05-02 16:12