diff options
Diffstat (limited to 'public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html')
| -rw-r--r-- | public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html | 460 |
1 files changed, 230 insertions, 230 deletions
diff --git a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html index b450a07..7546291 100644 --- a/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html +++ b/public/posts/2022-09-29/write-fizzbuzz-in-php-2-letters-per-line/index.html @@ -10,7 +10,7 @@ <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <title>【PHP】 fizzbuzz を書く。1行あたり2文字で。 | REPL: Rest-Eat-Program Loop</title> <link rel="stylesheet" href="/style.css?h=17cf97a767ec5fb6e64967729f40f30a"> - <link rel="stylesheet" href="/hl.css?h=208c52e3b7c9db1cad782c5d30b4698f"> + <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b"> </head> <body class="single"> <header class="header"> @@ -135,7 +135,7 @@ 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。 </p> - <pre class="highlight" language="c" linenumbering="unnumbered"><code>#\ + <pre class="highlight" language="c" linenumbering="unnumbered"><code class="highlight">#\ i\ n\ c\ @@ -143,7 +143,7 @@ l\ u\ d\ e\ -<\ +&lt;\ s\ t\ d\ @@ -151,14 +151,14 @@ i\ o\ .\ h\ ->\ -/* -*/ +&gt;\ +<span class="hljs-comment">/* +*/</span> i\ n\ t\ -/* -*/ +<span class="hljs-comment">/* +*/</span> m\ a\ i\ @@ -170,30 +170,30 @@ r( i\ n\ t\ -/* -*/ +<span class="hljs-comment">/* +*/</span> i= -1; -i< -1\ -0\ -0; +<span class="hljs-number">1</span>; +i&lt; +<span class="hljs-number">1</span>\ +<span class="hljs-number">0</span>\ +<span class="hljs-number">0</span>; i\ +\ +) -if +<span class="hljs-keyword">if</span> (i %\ -15 +<span class="hljs-number">15</span> == -0) +<span class="hljs-number">0</span>) p\ r\ i\ n\ t\ f( -"\ +<span class="hljs-string">"\ F\ i\ z\ @@ -204,11 +204,11 @@ z\ z\ %\ c\ -", -10 +"</span>, +<span class="hljs-number">10</span> ); -/* あとは同じように普通のプログラムを変形するだけなので省略 */</code></pre> +<span class="hljs-comment">/* あとは同じように普通のプログラムを変形するだけなので省略 */</span></code></pre> <p> バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 @@ -268,9 +268,9 @@ c\ また、2文字だと文字列がまともに書けないのも辛い。<code>''</code>だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>$a -=' -a' + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$a</span> +=<span class="hljs-string">' +a'</span> ;;</code></pre> <p> @@ -290,10 +290,10 @@ a' まずは普通に書くとしよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php -for ($i = 1; $i < 100; $i++) { - echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"; +<span class="hljs-keyword">for</span> (<span class="hljs-variable">$i</span> = <span class="hljs-number">1</span>; <span class="hljs-variable">$i</span> &lt; <span class="hljs-number">100</span>; <span class="hljs-variable">$i</span>++) { + <span class="hljs-keyword">echo</span> ((<span class="hljs-variable">$i</span> % <span class="hljs-number">3</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Fizz'</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Buzz'</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">"\n"</span>; }</code></pre> <p> @@ -307,13 +307,13 @@ for ($i = 1; $i < 100; $i++) { <code>for</code>は、3文字もある長いキーワードである。こんなものは使えない。<code>array_</code>系の関数を使って、適当に置き換えるとしよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php -$s = range(1, 100); -array_walk( - $s, - fn($i) => - printf((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), +<span class="hljs-variable">$s</span> = <span class="hljs-title function_ invoke__">range</span>(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>); +<span class="hljs-title function_ invoke__">array_walk</span>( + <span class="hljs-variable">$s</span>, + fn(<span class="hljs-variable">$i</span>) =&gt; + <span class="hljs-title function_ invoke__">printf</span>(((<span class="hljs-variable">$i</span> % <span class="hljs-number">3</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Fizz'</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Buzz'</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">"\n"</span>), );</code></pre> <p> @@ -327,17 +327,17 @@ array_walk( <code>range</code>、<code>array_walk</code>、<code>printf</code>は長すぎるのでどうにかせねばならない。ここで、PHP の可変関数を使う。可変関数とは、関数名が文字列として入った変数を経由して、関数を呼び出す機能である。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php -$r = 'range'; -$w = 'array_walk'; -$p = 'printf'; +<span class="hljs-variable">$r</span> = <span class="hljs-string">'range'</span>; +<span class="hljs-variable">$w</span> = <span class="hljs-string">'array_walk'</span>; +<span class="hljs-variable">$p</span> = <span class="hljs-string">'printf'</span>; -$s = $r(1, 100); -$w( - $s, - fn($i) => - $p((($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n"), +<span class="hljs-variable">$s</span> = <span class="hljs-variable">$r</span>(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>); +<span class="hljs-variable">$w</span>( + <span class="hljs-variable">$s</span>, + <span class="hljs-function"><span class="hljs-keyword">fn</span>(<span class="hljs-params"><span class="hljs-variable">$i</span></span>) =&<span class="hljs-title">gt</span></span>; + <span class="hljs-variable">$p</span>(((<span class="hljs-variable">$i</span> % <span class="hljs-number">3</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Fizz'</span>) . (<span class="hljs-variable">$i</span> % <span class="hljs-number">5</span> ? <span class="hljs-string">''</span> : <span class="hljs-string">'Buzz'</span>) ?: <span class="hljs-variable">$i</span>) . <span class="hljs-string">"\n"</span>), );</code></pre> <p> @@ -365,7 +365,7 @@ $w( というルールがない場合、「未定義の定数が評価された場合、その定数の名前が値になる」という PHP 7.x までの仕様が利用できる。例えば、<code>Fizz</code>という文字列が欲しければ、次のようにする。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>$f + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$f</span> =F .i .z @@ -376,13 +376,13 @@ $w( こうして簡単に文字列を作れる。なお、この仕様は 7.x 時点でも警告を受けるので、<code>@</code>演算子を使って抑制してやるとよい。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>$f + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$f</span> =@ F. @i -.# +.<span class="hljs-comment">#</span> @z -.# +.<span class="hljs-comment">#</span> @z ;;</code></pre> @@ -401,66 +401,66 @@ F. ずばり、文字列同士のビット演算を使う。PHP では、文字列同士でビット演算 (<code>&</code>、<code>|</code>、<code>^</code>) をした場合、文字列の各バイトごとに指定したビット演算がなされ、それを結合したものが演算結果となる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>$a = "12345"; -$b = "world"; + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$a</span> = <span class="hljs-string">"12345"</span>; +<span class="hljs-variable">$b</span> = <span class="hljs-string">"world"</span>; -// $a ^ $b は次のコードと同じ -$result = ''; -for ($i = 0; $i < min(strlen($a), strlen($b)); $i++) { -$result .= $a[$i] ^ $b[$i]; +<span class="hljs-comment">// $a ^ $b は次のコードと同じ</span> +<span class="hljs-variable">$result</span> = <span class="hljs-string">''</span>; +<span class="hljs-keyword">for</span> (<span class="hljs-variable">$i</span> = <span class="hljs-number">0</span>; <span class="hljs-variable">$i</span> &lt; <span class="hljs-title function_ invoke__">min</span>(<span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$a</span>), <span class="hljs-title function_ invoke__">strlen</span>(<span class="hljs-variable">$b</span>)); <span class="hljs-variable">$i</span>++) { +<span class="hljs-variable">$result</span> .= <span class="hljs-variable">$a</span>[<span class="hljs-variable">$i</span>] ^ <span class="hljs-variable">$b</span>[<span class="hljs-variable">$i</span>]; } -echo $result; -// => F]AXQ</code></pre> +<span class="hljs-keyword">echo</span> <span class="hljs-variable">$result</span>; +<span class="hljs-comment">// =&gt; F]AXQ</span></code></pre> <p> これを踏まえ、次のコードを見てみよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>$x = "x\nOm\n"; -$y = "\nk!\no"; -$r = $x ^ $y; -echo "$r\n";</code></pre> + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> = <span class="hljs-string">"x\nOm\n"</span>; +<span class="hljs-variable">$y</span> = <span class="hljs-string">"\nk!\no"</span>; +<span class="hljs-variable">$r</span> = <span class="hljs-variable">$x</span> ^ <span class="hljs-variable">$y</span>; +<span class="hljs-keyword">echo</span> <span class="hljs-string">"<span class="hljs-subst">$r</span>\n"</span>;</code></pre> <p> 実行すると、<code>range</code>が表示される。さて、PHP では文字列リテラル中に生の改行を直接書いてもよいのだった (「主な障害」の節を参照のこと)。書きかえてみよう。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>$x -='x + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> +=<span class="hljs-string">'x Om -'; -$y -=' +'</span>; +<span class="hljs-variable">$y</span> +=<span class="hljs-string">' k! -o' +o'</span> ; -$r = $x ^ $y; -echo "$r\n";</code></pre> +<span class="hljs-variable">$r</span> = <span class="hljs-variable">$x</span> ^ <span class="hljs-variable">$y</span>; +<span class="hljs-keyword">echo</span> <span class="hljs-string">"<span class="hljs-subst">$r</span>\n"</span>;</code></pre> <p> さらに<code>#</code>を使って適当に調整すると、次のようになる。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code>$x -=# -'x + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight"><span class="hljs-variable">$x</span> +=<span class="hljs-comment">#</span> +<span class="hljs-string">'x Om -'; -$y -=' +'</span>; +<span class="hljs-variable">$y</span> +=<span class="hljs-string">' k! -o' -;# -$r -=# -$x -^# -$y -;# +o'</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$r</span> +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +^<span class="hljs-comment">#</span> +<span class="hljs-variable">$y</span> +;<span class="hljs-comment">#</span> -echo "$r\n";</code></pre> +<span class="hljs-keyword">echo</span> <span class="hljs-string">"<span class="hljs-subst">$r</span>\n"</span>;</code></pre> <p> 1行あたり2文字で、<code>range</code>という文字列を生成することに成功した。他の必要な文字列にも、同様の処理をほどこす。 @@ -478,154 +478,154 @@ echo "$r\n";</code></pre> 完成したものがこちら。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php -$x -=# -'i -S' +<span class="hljs-variable">$x</span> +=<span class="hljs-comment">#</span> +<span class="hljs-string">'i +S'</span> ;; -$y -=' +<span class="hljs-variable">$y</span> +=<span class="hljs-string">' b! -'; -$c -=# -$x -^# -$y -;# -$x -=# -'x +'</span>; +<span class="hljs-variable">$c</span> +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +^<span class="hljs-comment">#</span> +<span class="hljs-variable">$y</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +=<span class="hljs-comment">#</span> +<span class="hljs-string">'x Om -'; -$y -=' +'</span>; +<span class="hljs-variable">$y</span> +=<span class="hljs-string">' k! -o' -;# -$r -=# -$x -^# -$y -;# -$x -=# -'k +o'</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$r</span> +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +^<span class="hljs-comment">#</span> +<span class="hljs-variable">$y</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +=<span class="hljs-comment">#</span> +<span class="hljs-string">'k Sk ~} Ma -'; -$y -=' +'</span>; +<span class="hljs-variable">$y</span> +=<span class="hljs-string">' x! s! k! -'; -$w -=# -$x -^# -$y -;# -$x -=# -'z +'</span>; +<span class="hljs-variable">$w</span> +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +^<span class="hljs-comment">#</span> +<span class="hljs-variable">$y</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +=<span class="hljs-comment">#</span> +<span class="hljs-string">'z Hd -G' -;# -$y -=' +G'</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$y</span> +=<span class="hljs-string">' x! ~! -'; -$p -=# -$x -^# -$y -;# -$x -=# -'L +'</span>; +<span class="hljs-variable">$p</span> +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +^<span class="hljs-comment">#</span> +<span class="hljs-variable">$y</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +=<span class="hljs-comment">#</span> +<span class="hljs-string">'L [p -'; -$y -=' +'</span>; +<span class="hljs-variable">$y</span> +=<span class="hljs-string">' c! -'; -$f -=# -$x -^# -$y -;# -$x -=# -'H +'</span>; +<span class="hljs-variable">$f</span> +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +^<span class="hljs-comment">#</span> +<span class="hljs-variable">$y</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +=<span class="hljs-comment">#</span> +<span class="hljs-string">'H [p -'; -$y -=' +'</span>; +<span class="hljs-variable">$y</span> +=<span class="hljs-string">' _! -'; -$b -=# -$x -^# -$y -;# -$b -[1 +'</span>; +<span class="hljs-variable">$b</span> +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$x</span> +^<span class="hljs-comment">#</span> +<span class="hljs-variable">$y</span> +;<span class="hljs-comment">#</span> +<span class="hljs-variable">$b</span> +[<span class="hljs-number">1</span> ]= -$c -(# -13 -*9 +<span class="hljs-variable">$c</span> +(<span class="hljs-comment">#</span> +<span class="hljs-number">13</span> +*<span class="hljs-number">9</span> ); -$s -=# -$r -(1 +<span class="hljs-variable">$s</span> +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$r</span> +(<span class="hljs-number">1</span> ,( -10 +<span class="hljs-number">10</span> ** -2) +<span class="hljs-number">2</span>) ); -$w -(# -$s -,# -fn -(# -$i -)# -=> -$p +<span class="hljs-variable">$w</span> +(<span class="hljs-comment">#</span> +<span class="hljs-variable">$s</span> +,<span class="hljs-comment">#</span> +<span class="hljs-function"><span class="hljs-keyword">fn</span> +(<span class="hljs-params"># +<span class="hljs-variable">$i</span> +</span>)# +=&<span class="hljs-title">gt</span></span>; +<span class="hljs-variable">$p</span> (( -(# -$i -%3 -?# -'' -:# -$f +(<span class="hljs-comment">#</span> +<span class="hljs-variable">$i</span> +%<span class="hljs-number">3</span> +?<span class="hljs-comment">#</span> +<span class="hljs-string">''</span> +:<span class="hljs-comment">#</span> +<span class="hljs-variable">$f</span> ). -(# -$i -%5 -?# -'' -:# -$b +(<span class="hljs-comment">#</span> +<span class="hljs-variable">$i</span> +%<span class="hljs-number">5</span> +?<span class="hljs-comment">#</span> +<span class="hljs-string">''</span> +:<span class="hljs-comment">#</span> +<span class="hljs-variable">$b</span> )? -:# -$i -)# -.' -') +:<span class="hljs-comment">#</span> +<span class="hljs-variable">$i</span> +)<span class="hljs-comment">#</span> +.<span class="hljs-string">' +'</span>) );</code></pre> </section> @@ -646,17 +646,17 @@ $i PHP では、バッククォートを使ってシェルを呼び出せる。これは<code>shell_exec</code>関数と等価である。さて、PHP ではバックスラッシュによる行継続が使えないと書いたが、シェルでは使える (当然だが、呼び出されるシェルに依存する。Bash なら大丈夫だろう。知らんけど)。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php -printf(` +<span class="hljs-title function_ invoke__">printf</span>(` e\ c\ h\ o\ \ -1\ -2\ -3\ +<span class="hljs-number">1</span>\ +<span class="hljs-number">2</span>\ +<span class="hljs-number">3</span>\ `);</code></pre> <p> @@ -685,34 +685,34 @@ o\ もうこれ以上は不可能だと思っていたのだが、この記事の執筆中に解決する方法を思いついたので載せておく。 </p> - <pre class="highlight" language="php" linenumbering="unnumbered"><code><?php + <pre class="highlight" language="php" linenumbering="unnumbered"><code class="highlight">&lt;?php -$c = 'chr'; +<span class="hljs-variable">$c</span> = <span class="hljs-string">'chr'</span>; ${ -'_ -'} -=# -$c -(# -32 +<span class="hljs-string">'_ +'</span>} +=<span class="hljs-comment">#</span> +<span class="hljs-variable">$c</span> +(<span class="hljs-comment">#</span> +<span class="hljs-number">32</span> ). -$c -(# -92 +<span class="hljs-variable">$c</span> +(<span class="hljs-comment">#</span> +<span class="hljs-number">92</span> ); -printf(` +<span class="hljs-title function_ invoke__">printf</span>(` e\ c\ h\ o\ ${ -'_ -'} -1\ -2\ -3\ +<span class="hljs-string">'_ +'</span>} +<span class="hljs-number">1</span>\ +<span class="hljs-number">2</span>\ +<span class="hljs-number">3</span>\ `);</code></pre> <p> @@ -720,8 +720,8 @@ ${ </p> <pre class="monospaced highlight"><code>${ -'_ -'}</code></pre> +'_ +'}</code></pre> <p> は変数で、中にはスペースとエスケープが入っている (<code>chr(32) . chr(92)</code>)。シェルに渡されている文字列は次のようになる。 @@ -749,8 +749,8 @@ o\ </p> <pre class="monospaced highlight"><code>${ -'_ -'}</code></pre> +'_ +'}</code></pre> <p> 最新版で警告が出るというのも美しくないので、私としては本編の解法を推す。 |
