From db3d51ddc421dad68abddb95d01ffdab440197d6 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 19 Mar 2023 03:24:43 +0900 Subject: feat(content): specify heading id --- .../write-fizzbuzz-in-php-2-letters-per-line.xml | 955 ++++++++++----------- 1 file changed, 477 insertions(+), 478 deletions(-) (limited to 'content/posts/2022-09-29') diff --git a/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.xml b/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.xml index d39526a..d828554 100644 --- a/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.xml +++ b/content/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line.xml @@ -19,7 +19,7 @@ -
+
記事の構成について この記事は、普通の fizzbuzz @@ -28,7 +28,7 @@ にソースコードがあるので、そちらを先に見てほしい。
-
+
レギュレーション PHP で、次のような制約の下に fizzbuzz を書いた。 @@ -62,7 +62,7 @@ off になっている環境が多いようなので、今回は使わないことにした。
-
+
主な障害 1行あたりの文字数など、適当に改行を挟めばいいだけではないのか? @@ -182,541 +182,540 @@
- 標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと) - - -
- - に反する - (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。 - - - また、2文字だと文字列がまともに書けないのも辛い。'' だけで - 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP - では文字列リテラル中に生の改行が書けるので - - - - - - とすると $a"\na" になるのだが、余計な改行が入ってしまう。 - - - これらの障害をどのように乗り越えるのか、次節から見ていく。 - -
-
- 解説 -
- 普通の (?) fizzbuzz + 標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと) + + - まずは普通に書くとしよう。 + に反する + (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。 + + + また、2文字だと文字列がまともに書けないのも辛い。'' だけで + 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP + では文字列リテラル中に生の改行が書けるので - 素直に書いた fizzbuzz - とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 + とすると $a"\na" になるのだが、余計な改行が入ってしまう。 -
-
- <literal>for</literal> の排除 - for - は、3文字もある長いキーワードである。こんなものは使えない。array_ - 系の関数を使って、適当に置き換えるとしよう。 + これらの障害をどのように乗り越えるのか、次節から見ていく。 - - +
+ 解説 +
+ 普通の (?) fizzbuzz + + まずは普通に書くとしよう。 + + + + + + 素直に書いた fizzbuzz + とは言い難いが、このくらいは普通だということにしておかないと、この先がやっていられないので許してほしい。 + +
+
+ <literal>for</literal> の排除 + + for + は、3文字もある長いキーワードである。こんなものは使えない。array_ + 系の関数を使って、適当に置き換えるとしよう。 + + + - printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), - ); - ]]> - - - array_walkrangeprintf といった for - よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、echo - は文 (statement) であり式 (expression) ではないので、式である printf - に置き換えた。 - + printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), + ); + ]]> + + + array_walkrangeprintf といった for + よりも長いトークンが現れてしまったが、これは次節で直すことにする。なお、echo + は文 (statement) であり式 (expression) ではないので、式である printf + に置き換えた。 + +
+
+ 関数呼び出しの短縮 + + rangearray_walkprintf + は長すぎるのでどうにかせねばならない。ここで、PHP + の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 + + + + $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), + ); + ]]> + + + これで関数を呼び出している所は短くなった。では、$r$w や + $p、また 'Fizz''Buzz' はどうやって + 1行2文字に収めるのか。次のテクニックへ移ろう。 + +
+
+ 余談: PHP 8.x で動作しなくてもいいなら + + 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。 + +
+ + PHP 7.4〜8.1 で動作すること + +
+ + というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という + PHP 7.x までの仕様が利用できる。例えば、 Fizz + という文字列が欲しければ、次のようにする。 + + + + + + こうして簡単に文字列を作れる。なお、この仕様は 7.x + 時点でも警告を受けるので、@ 演算子を使って抑制してやるとよい。 + + + + + + むしろ、このことがわかっていたからこそ PHP 8.x + での動作を要件に課したところがある。 + +
+
+ 文字列リテラルの短縮 + + 実際に使った手法の説明に移る。 + + + ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 + (&|^) + をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。 + + + F]AXQ + ]]> + + + これを踏まえ、次のコードを見てみよう。 + + + + + + 実行すると、range が表示される。さて、PHP + では文字列リテラル中に生の改行を直接書いてもよいのだった + (「主な障害」の節を参照のこと)。書きかえてみよう。 + + + + + + さらに # を使って適当に調整すると、次のようになる。 + + + + + + 1行あたり2文字で、range + という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。 + + + 備考: Buzz 中にある小文字の u は、このロジックだと non-printable + な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。 + +
-
- 関数呼び出しの短縮 +
+ 完成系 - rangearray_walkprintf - は長すぎるのでどうにかせねばならない。ここで、PHP - の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 + 完成したものがこちら。 - $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), + $x + =# + 'i + S' + ;; + $y + =' + b! + '; + $c + =# + $x + ^# + $y + ;# + $x + =# + 'x + Om + '; + $y + =' + k! + o' + ;# + $r + =# + $x + ^# + $y + ;# + $x + =# + 'k + Sk + ~} + Ma + '; + $y + =' + x! + s! + k! + '; + $w + =# + $x + ^# + $y + ;# + $x + =# + 'z + Hd + G' + ;# + $y + =' + x! + ~! + '; + $p + =# + $x + ^# + $y + ;# + $x + =# + 'L + [p + '; + $y + =' + c! + '; + $f + =# + $x + ^# + $y + ;# + $x + =# + 'H + [p + '; + $y + =' + _! + '; + $b + =# + $x + ^# + $y + ;# + $b + [1 + ]= + $c + (# + 13 + *9 + ); + $s + =# + $r + (1 + ,( + 10 + ** + 2) + ); + $w + (# + $s + ,# + fn + (# + $i + )# + => + $p + (( + (# + $i + %3 + ?# + '' + :# + $f + ). + (# + $i + %5 + ?# + '' + :# + $b + )? + :# + $i + )# + .' + ') ); ]]> +
+
+ 感想など - これで関数を呼び出している所は短くなった。では、$r$w や - $p、また 'Fizz''Buzz' はどうやって - 1行2文字に収めるのか。次のテクニックへ移ろう。 + PHP は、スクリプト言語の中だとシンタックスシュガーが少ない + (体感)。この挑戦は不可能に思われたが、PHP + マニュアルとにらめっこしていたらなんとかなった。 -
-
- 余談: PHP 8.x で動作しなくてもいいなら - 今回使ったテクニックを説明する前に、余談として、文字列リテラルの短縮法として今回採用しなかったものを紹介する。 + みんなもプログラムを細長くしよう。 -
- - PHP 7.4〜8.1 で動作すること - -
+
+
+ 余談2: 別解 - というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という - PHP 7.x までの仕様が利用できる。例えば、 Fizz - という文字列が欲しければ、次のようにする。 + PHP では、バッククォートを使ってシェルを呼び出せる。これは shell_exec + 関数と等価である。さて、PHP + ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える + (当然だが、呼び出されるシェルに依存する。Bash + なら大丈夫だろう。知らんけど)。 - こうして簡単に文字列を作れる。なお、この仕様は 7.x - 時点でも警告を受けるので、@ 演算子を使って抑制してやるとよい。 + なお、ここでは簡単のため出力に printf をそのまま使っているが、実際には + printf という文字列を合成して可変関数で呼び出す。 - - - - むしろ、このことがわかっていたからこそ PHP 8.x - での動作を要件に課したところがある。 + ただし、これでは -
-
- 文字列リテラルの短縮 +
+ + スペースやタブを使用しないこと + +
- 実際に使った手法の説明に移る。 + に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。 - ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 - (&|^) - をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。 + もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 F]AXQ + printf(` + e\ + c\ + h\ + o\ + ${ + '_ + '} + 1\ + 2\ + 3\ + `); ]]> - これを踏まえ、次のコードを見てみよう。 + 先程と同じく、chrprintf を生成する部分は長くなるので省いた。 - + - + - 実行すると、range が表示される。さて、PHP - では文字列リテラル中に生の改行を直接書いてもよいのだった - (「主な障害」の節を参照のこと)。書きかえてみよう。 + は変数で、中にはスペースとエスケープが入っている + (chr(32) . chr(92))。シェルに渡されている文字列は次のようになる。 - + - + - さらに # を使って適当に調整すると、次のようになる。 + これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz + のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう + (試してないけど)。 - - - - 1行あたり2文字で、range - という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。 + ということでこれは別解ということにしておく。 - 備考: Buzz 中にある小文字の u は、このロジックだと non-printable - な文字になってしまう。ここまでのテクニックを駆使すれば回避するのはそう難しくないので、考えてみてほしい。 + ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。 + + + + + + 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。
-
-
- 完成系 - - 完成したものがこちら。 - - - - $p - (( - (# - $i - %3 - ?# - '' - :# - $f - ). - (# - $i - %5 - ?# - '' - :# - $b - )? - :# - $i - )# - .' - ') - ); - ]]> - -
-
- 感想など - - PHP は、スクリプト言語の中だとシンタックスシュガーが少ない - (体感)。この挑戦は不可能に思われたが、PHP - マニュアルとにらめっこしていたらなんとかなった。 - - - みんなもプログラムを細長くしよう。 - -
-
- 余談2: 別解 - - PHP では、バッククォートを使ってシェルを呼び出せる。これは shell_exec - 関数と等価である。さて、PHP - ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える - (当然だが、呼び出されるシェルに依存する。Bash - なら大丈夫だろう。知らんけど)。 - - - - - - なお、ここでは簡単のため出力に printf をそのまま使っているが、実際には - printf という文字列を合成して可変関数で呼び出す。 - - - ただし、これでは - -
- - スペースやタブを使用しないこと - -
- - に違反してしまう。スペースが使えないと引数とコマンドを区切れない。これは困った。 - - - もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 - - - - - - 先程と同じく、chrprintf を生成する部分は長くなるので省いた。 - - - - - - は変数で、中にはスペースとエスケープが入っている - (chr(32) . chr(92))。シェルに渡されている文字列は次のようになる。 - - - - - - これは、前掲したコマンドと同じだ。かくして、スペースを陽に書かずにシェルをおおよそ自由に扱えるようになった。Fizzbuzz - のワンライナーくらいすぐ書けるだろうから、あとはなんとかなるだろう - (試してないけど)。 - - - ということでこれは別解ということにしておく。 - - - ちなみに、PHP 8.2 からは、この記法で Warning が出るようになるようだ。 - - - - - - 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。 - -
-- cgit v1.2.3-70-g09d2