回答:
変数と空白がPHPの言語構成要素と相互作用する方法を理解します。
私の(確かに短い)時間のゴルフでは、PHPの言語構造(例:echo、return、for、whileなど)が変数や空白とやり取りするときに直感的ではない方法で動作することがわかりました。
echo$v;、たとえば、完全に有効でありreturn$v;、他の同様の構成要素です。空白のこれらのわずかな減少は、長さの大幅な累積的減少につながります。
ただし、次の例のように、言語構造の前の変数には後にスペースが必要であることに注意してください。
foreach($a AS$b){}
AS言語構成体であるため、変数の前にスペースは必要ありません$bが、その前のスペースを省略すると、結果$aASとして変数名として解析され、構文エラーが発生します。
foreach($a[1]as$b)空白は不要です。これは、言語の構成要素や変数に関するものではなく、異なる単語の単語文字間のスペースに関するものです。
echo $a+5." text"ある.とPHPが判断するため、機能しません5。それを動作させるために、あなたはこのようにスペースを追加する必要があります:echo $a+5 ." text"
echo$a+5," text";。このecho構造により、複数のパラメーターを渡すことができます。書くecho"result: ".($a+5)."!";必要があるところに、あなたは書くことができますecho"result: ",$a+5,"!";。実際、複数のパラメーターをに渡すことはecho、コードの実行速度が少し速くなるため(出力を連結せずに個別に送信するため)最適化されています。最速のコードを書くことに関する課題については、これは小さな小さな小さなビットを助けるかもしれません。
echoが、いないと、print(あなたが表現の中に置く場合は、必要がある:echoながら、戻り値のない純粋な構造であるprint ことができます機能として動作:それは括弧を必要としませんが、それは常に戻りますint(1)。
print。
文字列を賢く使用してください。
この答えは2つあります。最初の部分は、文字列を宣言するときに、PHPの不明な定数から文字列への暗黙的な変換を利用して、スペースを節約できることです。たとえば、
@$s=string;
@これが生成されます警告を無効にする必要があります。全体的に、1文字の削減になります。
変数を頻繁に使用される関数の名前に設定すると、スペース効率がよくなる場合があります。通常、次のものがあります。
preg_match(..);preg_match(..);
しかし、ゴルフをするとき、これは簡単に短くできます:
@$p=preg_match;$p(..);$p(..);
「preg_match」のインスタンスが2つだけの場合、1文字しか保存しませんが、関数を使用するほど、保存できるスペースが増えます。
E_DEPRECATED)は受け入れ可能です
php.iniたファイル
常に条件付きチェックを記述する必要はありません。たとえば、一部のフレームワークはファイルの先頭でこれを使用してアクセスをブロックします。
<?php defined('BASE_PATH')||die('not allowed');
または通常の機能で
$value && run_this();
の代わりに
if($value) { run_this(); }
PHP 5.4以降、配列はarray()関数の代わりに角かっこ(JavaScriptと同様)を使用して宣言できます。
$arr=['foo','bar','baz'];
// instead of
$arr=array('foo','bar','baz');
5バイト節約されます。
しかし、連想配列に「穴」がある場合、バイト数がかかる場合があります。
$arr=array(,1,,3,,5);
// is one byte shorter than
$arr=[1=>1,3=>3,5=>5];
「空の」値で穴を埋めることができる場合、デメリットは少し後にヒットします。
$arr=[0,1,0,3,0,5,0,7,0,9,10,11];
// costs two byte more than
$arr=array(,1,,3,,5,,7,,9,,11);
[,$a,$b,$c]=$argv;。
配列操作を実行していない限り、配列インデックスへのほとんどの参照$a[$i]は単にに置き換えることができます$$i。これは、インデックスが整数の場合にも当てはまります。整数はPHPで有効な変数名であるためです(リテラルにはブラケットが必要です(例:)${0})。
Rabonowitz Wagonスピゴットの次の実装を検討してください。
3.<?for(;$g?$d=0|($a[$g]=$d*$g--/2+($a[$g]?:2)%$g*1e4)/$g--:238<<printf($e?'%04d':'',$e+$d/$g=1e4)^$e=$d%$g;);
これは、両方の配列参照$a[$g]を$$g代わりに置き換えるだけで、6バイト改善できます。
3.<?for(;$g?$d=0|($$g=$d*$g--/2+($$g?:2)%$g*1e4)/$g--:238<<printf($e?'%04d':'',$e+$d/$g=1e4)^$e=$d%$g;);
ライブラリ関数の大規模なサブセットを学習します。
PHPのライブラリは非常に巨大で、さまざまなタスクを大幅に短縮できる便利な関数を多数提供しています。何かをしようとするたびに検索することもできますが、時間を無駄にすると特定の検索に一致するものが見つからない場合があります。最善の方法は、ライブラリに精通し、関数名とその機能を記憶することです。
文字列内で関数を実行します。
これを試して:
$a='strlen';
echo "This text has {$a('15')} chars";
またはこれを試してください:
//only php>=5.3
$if=function($c,$t,$f){return$c?$t:$f;};
echo <<<HEREDOCS
Heredocs can{$if(true,' be','not be')} used too and can{$if(<<<BE
{$if(true,1,0)}
BE
,'','not')} be nested
HEREDOCS;
//Expected output: Heredocs can be used too and can be nested
これは""、とheredocs を使用した文字列でのみ機能します(nowdocsと混同しないでください)。
ネストされた関数の使用は、ネストされたheredocs内でのみ可能です(または解析エラーが発生します)!
you will run into parse errors自分で読めませんか?どのように厄介なのZendエンジンは、この一緒に入れない
!!$foo真理値をtrue(または1出力)に、偽値(0、空の文字列、空の配列)をfalse(または空の出力)に変換します。
これは、コードゴルフではほとんど必要ありません。とにかく暗黙のキャスト。
(int)$foo$foo|0またはとして記述できますが、foo^0括弧が必要な場合があります。
ブール値と文字列の場合、$foo*1または+$foointにキャストするために使用できます。
10するには、ゼロを追加できます:*10-> .0。ただし、この場合、PHPはドットを小数点として使用して文句を言います。(文字列にゼロの可変量がある場合は異なります。)joinには代わりにimplode。join($a)と同じですjoin('',$a)$s=a;$s++;生成すること$s=b;です。これは、大文字と小文字で機能します。$s=Z;$s++;結果はになり$s=AA;ます。aZto bA、A1to A2、A9to B0およびz99Zto aa00A。文字列でNULL)。$n="001";$n++;生産$n="002";。彼らがそれを取り除いたのは少し残念です。どんなゴルフでも:常にオペレーター優先順位表を手元に用意してください。
通常のコードでは、<?phpand を使用することをお勧めします?>。しかし、これは通常のコードではありません -あなたはコードゴルフコードを書いています。代わりに<?php、を書き<?ます。代わりに<?php echo、を書き<?=ます。?>最後に入力しないでください-それは完全にオプションです。?>何らかの理由で必要な場合(たとえば、テキストを出力するために、何らかの形で短くなっている場合など)、セミコロンを前に置かないでください?>。セミコロンを意味するため、必要ありません。
間違っている(間違いなく長すぎる):
<?php echo ucfirst(trim(fgets(STDIN)));?>s!
正しい:
<?=ucfirst(trim(fgets(STDIN)))?>s!
文字列をループする
26バイトまたは24から18までで実行できます。
foreach(str_split($s)as$c) # A) 26 - general
for($p=0;a&$c=$s[$p++];) # B) 24 - general
for($p=0;$c=$s[$p++];) # C) 22 - if $s has no `0` character
for(;a&$c=$s[$p++];) # D) 20 - if $p is already NULL or 0 (does NOT work for false)
for(;$c=$s[$p++];) # E) 18 - both C and D
for(;$o=ord($s[$p++]);) # F) 23 - work on ASCII codes, if $s has no NULL byte and D
for(;~$c=$s[$p++];) # G) 19 - if $s has no chr(207) and D
$a&$bビット単位のAND(のASCIIコード)文字でにない$aと$b
の短いものと同じ長さを持つ文字列での結果$aとは$b。
ord($s[$p++])、代替としてfor(;$s+=ord($argv[++$i])%32?:die($s==100););に対して、for(;$c=$argv[++$i];)$s+=ord($c)%32;echo$s==100;この質問にcodegolf.stackexchange.com/questions/116933/...
~数字のみで作業している場合に追加してください
~$cアプローチに対して警告が生成されることに注意してください。
if(a==2){some code;}else{some other code;}
これに短縮できます:
(a==2?some code:some other code);
もっと短い?
a?aa:ab?aba:abb:b評価し(a?aa:ab)?(aba):(abb)ます。
$a?:$b同じ$a?$a:$bです。
||は、PHPでブール値にキャストします。
つかいます ...
join の代わりに implodechop代わりにrtrim(chopPERLでは違います!)die の代わりに exitfputs の代わりに fwriteis_intis_integerまたはの代わりにis_longis_realis_floatまたはの代わりにis_doublekey_exists の代わりに array_key_existsmysql の代わりに mysql_db_query...最も重要なエイリアスに名前を付けます。詳細については、http://php.net/aliasesをご覧ください。
dieパラメータの有無にかかわらず動作することを知っていましたか?die(1)エラーコードでプログラムを終了します1(これについては完全にはわかりません。テストが必要です)。dieはコード0でdie("Hello")終了し0、印刷後にコードで終了しますHello。
+演算子とマージできます。の代わりに:
$merged = array_merge($a, $b);
つかいます:
$merged = $a + $b;
+演算子はインデックス付き配列でも動作しますが、おそらくあなたが望むことをしないことに注意してください。
+インデックスが異なる限り、数値配列もを使用してマージできます。そうでない場合、最初の配列の値は2番目の配列の値で上書きされます(array_mergeと同様)。違い:+インデックスを並べ替えません。
つかいます
array_flip($array)[$value]
の代わりに
array_search($value,$array)
各値の出現が一意である配列に1バイトを保存する
変数変数に関するいくつかの興味深い事実
それらを共有する必要がありました(少なくとも1つがゴルフに役立つことを確認する前でも)。
$x=a;$$x=1;$x++;$$x=2;echo"$a,$b";印刷します1,2$a=1;$$a=5;$a++;$$a=4;${++$a}=3;echo${1},${2},${3};プリント543。[0-9a-zA-Z_]変数名だけでなく、すべての文字列:printsに使用でき$x="Hello!";$$x="Goodbye.";echo${"Hello!"};ますGoodbye.。[a-zA-Z_][a-zA-Z_0-9]*変数名以外はすべて、リテラル使用のために中括弧が必要です。$$x=1sets ${NULL}は${false}andと同じ${""}です。 $a=1;$$a=5;設定されないばかり${1}でなく、${true}。
もう1つ、これまで見つけた中で最も奇妙なもの:試してみてください$a=[];$$a=3;echo${[]};。はい、印刷され3ます!
このほとんどの理由:変数名は常に文字列に評価されます。
(指摘してくれた@Christophに感謝します。)
だから、あなたprintやecho式で得たものは何でも、変数名として得られるものです。
[]変換Array:${[]} = 5;echo $Array;プリント5。あなたはそれを知っていると確信していますが、誰にとっても明らかではないかもしれません:)
可能な限り引用符を避けます
PHPは、不明な単語を暗黙的にリテラル文字列にキャストします。
$foo=foo;$foo='foo';(fooキーワードでも定義済み定数でもないことを前提とする)と同じです:$foo=echo;動作しません。
しかし:$p=str_pad;しません; と$p(ab,3,c)評価しabcます。
引用符なしで文字列リテラルを使用すると、Use of undefined constant; に対する通知が生成されます。ただし、error_reporting(CLIパラメーター-n)のデフォルト値を使用する場合は表示されません。
-nフラグで表示できます)。7.2は警告を生成します。それ以降のバージョンではエラーが発生します!
PHP 7.4は現在RC2バージョンであり、約2か月後にリリースされることを期待しています。新機能のリストはこちら(このページは7.4のリリース時に実際に更新できます)。7.4では、PHPについに矢印関数が追加されたため、関数の応答が短くなるだけでなく、クロージャーを他の関数に渡すことも大幅に短くなります。以下に例を示します。
入力を返す+ 1:
匿名関数(クロージャー)-25バイト- オンラインで試してください!
function($n){return$n+1;}
Arrow function-12 bytes- オンラインで試してみてください!
fn($n)=>$n+1
最初の入力(intの配列)の項目を2番目の入力(int)で乗算します。
無名関数(クロージャ)-72バイト- オンラインで試してみてください!
function($a,$n){return array_map(function($b)use($n){return$b*$n;},$a);}
矢印関数-38バイト- オンラインで試してみてください!
fn($a,$n)=>array_map(fn($b)=>$b*$n,$a)
ステートメント$nなしで内部関数でアクセスできることに気付きましたuse $nか?ええ、それは矢印機能の特徴の1つです。
以下のように我々は彼らに名前を付けることができないので、注意点として、私は、(それ自体の内部で同じ矢印の関数を呼び出す)を再帰的に仕事に機能矢印得ることができませんでしたし、変数でクロージャとしてそれらを保存する$fことはありません$fアクセスwithing自体は(悲しいです)。したがって、この例は機能せず$f、最初の行で使用すると致命的なエラーが発生します。
$f=fn($n)=>$n?$f($n-1):0;
$f(5); // Causes error: "PHP Notice: Undefined variable: f" + "PHP Fatal error: Uncaught Error: Function name must be a string"
ただし、別の矢印関数を使用して矢印関数を呼び出すと機能します。
$f1=fn($n)=>$n+1;
$f2=fn($n)=>$f1($n-1);
$f1(2) // Returns 3
$f2(2) // Returns 2
$f=fn($n)=>$n?$f($n-1):0;あなたが$f=$F=fn($n)=>$n?$F($n-1):0;?それはうまくいくでしょうか?そして、あなたは$(5)いつものように電話します。
たとえば、これの代わりに:
$a = foo();
echo $a[$n];
できるよ:
echo foo()[$n];
これはメソッドでも機能します:
echo $obj->foo()[$n];
配列宣言を直接逆参照することもできます。
echo [1, 2, 3, 4, 5][$n];
end()代わりに使用array_pop()このend()関数は、内部ポインタを配列の最後に移動するだけでなく、最後の値も返します。もちろん、その値は削除されないことに注意してください。したがって、後で配列に何が含まれているか気にしない場合は、の代わりに使用できますarray_pop()。
この特殊なケースでは、ダブルのarray_flipが10バイトを節約します
($f=array_flip)($k=$f($c)))配列内のすべてのdouble型の値を削除し、私はこれを落としてきた$c=[],、|in_array($o,$c)と置き換えるarray_keys($c)と$k
for([,$x,$y]=$argv;a&$o=$y[$i];$i++)
$x[$i]==$o?:$c[$x[$i]]=$o; # if char string 1 not equal char string 2 set key=char1 value=char2
echo strtr($x,($f=array_flip)($k=$f($c)))==$y # boolean replacement string 1 equal to string 2
?join($k)." ".join($c) # output for true cases
:0; #Output false cases
に対して
for($c=[],[,$x,$y]=$argv;a&$o=$y[$i];$i++)
$x[$i]==$o|in_array($o,$c)?:$c[$x[$i]]=$o; # if char string 1 not equal char string 2 set key=char1 value=char2
echo strtr($x,$c)==$y # boolean replacement string 1 equal to string 2
?join(array_keys($c))." ".join($c) # output for true cases
:0; #Output false cases
array_uniqueに対して2バイトを節約します
for([,$x,$y]=$argv;a&$o=$y[$i];$i++)
$x[$i]==$o?:$c[$x[$i]]=$o; # if char string 1 not equal char string 2 set key=char1 value=char2
echo strtr($x,array_unique($c))==$y # boolean replacement string 1 equal to string 2
?join(array_keys($c))." ".join($c) # output for true cases
:0; #Output false cases
このプログラムのバグを見つけ$x[$i]==$o?:$c[$x[$i]]=$oて($p=$x[$i])==$o?:$k[$c[$p]=$o]=$p、二重のarray_flip への置き換えが必要なくなった後
array_unique。わーい!
交差する文字列
使用したことがありますか
join("DELIMITER",str_split($s))としても(31バイト)または
preg_replace(".","DELIMITER",$s)(32バイト)
?
そのためのビルトイン:
試してくださいchunk_split($s,1,"DELIMITER")(29バイト)。
3番目のパラメーターを省略すると、 chunk_split\r\n ; が使用されます。7バイトまたは8バイト節約できます。
しかし注意してください: chunk_split文字列に区切り文字も追加します。
正確に必要なものが得られない場合があります。
(チャンクの長さを指定しない場合、76が使用されます。コードゴルフではなく、珍しいですが、誰が知っています。)
strtr私はこのアイデアが大好きであると組み合わせて例を追加する必要があります。
配列内の最小値のケース検索では、代わりに使用できます
unset($var[$k]);
$var[$k]=INF;
3バイトを保存するには
場合によっては、文字の入力があり、文字ごとにゼロより大きい入力で繰り返し出力する必要があります。
for(;--$z?:($c=$argn[$i++]).$z=$argn[$i++];)echo$c;
(52バイト)は
for(;~$c=$argn[$i++];)echo str_repeat($c,$argn[$i++]);
または
for(;~$c=$argn[$i++];)echo str_pad($c,$argn[$i++],$c);
(各54バイト)
a1b2c1$z設定されていない(暗黙的NULL)ため、--$z何もせず、偽りです。
$c="a"、$z="1"そして$i=2-> $c.$z="a1"は真実です->出力"a"
--$z=0; したがって、を設定$c="b"します$z="2"(および$i=4)-> $c.$z="b2"is truthy-> output"ab"
--$z=1 ->出力 "abb"
--$z=0; 設定$c="c"し$z=1 $c.$z="c1"て真の出力です"abbc"
--$z=0そう$c=""と$z=""- > $c.$z=""であるfalsy - >ループブレーク
forループを結合する次の形式のコードがあるとします:
for($pre1; $cond1; $post1) for($pre2; $cond2; $post2) $code;
これは通常、次の形式で再ロールできます。
for($pre1; $cond2 • $post2 || $cond1 • $pre2 • $post1; ) $code;
where •は、一般的な結合演算子を表します。通常、これによりバイト数が削減されますが、おそらくある程度の創造性が必要になります。$cond2最初に失敗するように書く必要があります。$post1また、最初の実行に失敗する必要がありますが、事前にリファクタリングする方が簡単な場合があります。$post1が、存在しない場合はません。
3つ以上のネストされたループで作業している場合は、最初に2つを組み合わせてから、別のループに組み合わせることもできます。一般に、内側から外側に結合する方が簡単であることがわかりました。
例として、Hカーペットフラクタル(97バイト)に対する次のソリューションを考えます。
for(;$i<$n=3**$argn;$i+=print"$s\n")for($s=H,$e=1;$e<$n;$e*=3)$s.=str_pad($i/$e%3&1?$s:'',$e).$s;
これは、次の方法で再定式化できます。
for(;($i+=$e&&print"$s\n")<$n=3**$argn;)for($s=H,$e=1;$e<$n;$e*=3)$s.=str_pad($i/$e%3&1?$s:'',$e).$s;
$e&&printprint最初の繰り返しを防ぎ、また増分しません$i。
そして最後に(93バイト):
for(;$H>$e*=3or$e=($i+=$e&&print"$s\n")<${$s=H}=3**$argn;)$s.=str_pad($i/$e%3&1?$s:'',$e).$s;
$H>$e*=3 両方の変数が未定義であるため、最初に失敗します。
join(explode(" ",$string));
と比較して1文字節約
str_replace(" ","",$string);
""とにかくあまり役に立ちません。
)。そしてstrtr($string,[" "=>""])さらに短いです。
array_push($a,...$b);
より1バイト短い
$a=array_merge($a,$b);
連想配列では同じように機能しません
strtoupper()andの代わりにブール演算子を使用しますstrtolower()アルファベット文字で構成される文字列のみを使用している場合は、ブール演算子を使用して、PHPの組み込み関数よりも少ないキーストロークで大文字または小文字に変更できます。
// Convert lowercase to uppercase
$s = "g";
echo strtoupper($s); // Outputs 'G', uses 20 characters
echo~" "&$s; // Outputs 'G', uses 12 characters
// Convert uppercase to lowercase
$s = "G";
echo strtolower($s); // Outputs 'g', uses 20 characters
echo$s^" "; // Outputs 'g', uses 11 characters
// Switch case of each character
$s = "Gg";
echo$s^" "; // Outputs 'gG', uses 12 characters
任意の長さの文字列の場合は少し複雑ですが、&and ^演算子は結果を短い入力文字列の長さに切り捨てます。たとえば、if $Wが少なくともinput $sと同じ長さのスペースの文字列である場合、と~$W&$s同等でありstrtoupper($s)、と$s|$W^$s同等ですstrtolower($s)(一方$s|$W、$sと$Wが同じ長さでない限り、それ自体が追加のスペースを持つ文字列を生成します)。