今更だけどFizzBuzz問題(正規表現で)
2010-01-06-1 / カテゴリ: [programming][正規表現][perl] / [permlink]
更にPerlネタ
昨日([2010-01-05-1])に引き続き他人の日記をこっそり覗き見しているとFizzBuzz問題のPerlのコードを発見。
2年位前に結構盛り上がってたみたいだけど、何故かリアルタイム参戦してなかったので、ちょっとやってみた。
が、何のヒネリも入らなかった。
んで、件のエントリに
(ググったらそのものズバリな正規表現でFizzBuzzは見つかったけど、手持ちスキルはPerl5.8止まりなのでよくわからんかったorz <- 何がPerl使いだ>自分)
とりあえず解説。
処理の流れ: 5倍数時は"数字Buzz"に置換、3倍数時は"数字Fizz"に置換、最後に数字以外が付加されていれば数字を削除して出力する。先に5を処理してるのは "5か0 + (非数字があるか空)" のパターンでキャプチャ不使用で末尾にBuzzを付加するパターン置換がどうしてもできなかったからorz
Cだと
あ、多分当時はCに毒されてPerlを忘れつつあったから、面倒がって流行に乗らなかったのかも。(2007年のprogrammingカテがCばっか…)
昨日([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行目: 出力
Cだと
for (...);ってできるけど。
あ、多分当時はCに毒されてPerlを忘れつつあったから、面倒がって流行に乗らなかったのかも。(2007年のprogrammingカテがCばっか…)
置換時に式を評価する
2007-02-09-3 / カテゴリ: [perl][正規表現] / [permlink]
/e で。割とよく使われてるはずだからサンプルだけ
C/C++ ソースの #ifdef を削る。
/m で複数行マッチ処理を行ってる場合、式の途中の ^ は改行直後の位置にマッチする。
else 節がない場合は $4 は空になるのでバッサリ削られる。
C/C++ ソースの #ifdef を削る。
@define = qw/__DEBUG __WRITELOG/; # define を指定する # $src にソースを丸ごとつっこむ # #if-#endif $src =~ s|^#if\s+(\w+)(.*?)^(#else(.*?))?^#endif|($1)?$2:$4|emsg; # #ifdef-#endif $src =~ s|^#ifdef\s+(\w+)(.*?)^(#else(.*?))?^#endif|(grep {$_ eq $1 } @define)?$2:$4|emsg; # #ifndef-#endif $src =~ s|^#ifndef\s+(\w+)(.*?)^(#else(.*?))?^#endif|(grep {$_ eq $1 } @define)?$4:$2|emsg;/m で複数行マッチ、/s で . を改行にマッチさせる。
/m で複数行マッチ処理を行ってる場合、式の途中の ^ は改行直後の位置にマッチする。
else 節がない場合は $4 は空になるのでバッサリ削られる。
前回のマッチ位置から処理する
2007-02-09-2 / カテゴリ: [perl][正規表現] / [permlink]
単に繰り返したい場合は
けど、ある正規表現にマッチした場合、その内容によって以降の処理が変化させたい、などのちょっと複雑(?)な場合は、/c /g によって、マッチ箇所を記憶させ、次に \G でその位置を参照できる。
/regexp/g;/g オプションで、繰り返し処理される。
けど、ある正規表現にマッチした場合、その内容によって以降の処理が変化させたい、などのちょっと複雑(?)な場合は、/c /g によって、マッチ箇所を記憶させ、次に \G でその位置を参照できる。
《続きを読む》
エスケープされていないダブルクォート
2007-02-09-1 / カテゴリ: [perl][正規表現] / [permlink]
こんな感じかな。
否定後読みの (?<!\\) がないと、奇数個の逆スラッシュは、偶数個分だけが(?:\\\\)*にマッチしてしまうので NG。
$reg = qr/(?<!\\)(?:\\\\)*\"/;手前に \ がなくて、\\ が0個以上あって " の場合。
否定後読みの (?<!\\) がないと、奇数個の逆スラッシュは、偶数個分だけが(?:\\\\)*にマッチしてしまうので NG。
ascii文字の正規表現
2005-07-08-2 / カテゴリ: [programming][perl][command][正規表現] / [permlink]
m/[ -~]/0x20(スペース)から0x7e(チルダ)まで。
0x20未満のハードタブ(0x09)や改行(0x0A)は個別に対処せよ。
0x7F(DEL)はいらねーよな。
あぁ、grep でも使える
$ command | grep -v '[ -~]'asciiを含まない行を出力
$ command | grep '[^ -~]'ascii以外を含む行を出力
lv(v.4.50, v.4.51)の正規表現検索は、スペースを範囲に含めると overcrossing range と出力されて効かないので、0x21の!から指定する
/[^ !-~]ascii以外(タブなど除く)を含む行を出力
less(351, 358)は [ -~]で大丈夫なんだけどなぁ。意外にも more も大丈夫だ。
最終更新時間: 2013-05-02 16:12