답변:
변수와 공백이 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.
현명하게 끈을 사용하십시오.
이 답변은 두 가지입니다. 첫 번째 부분은 문자열을 선언 할 때 공간을 절약하기 위해 PHP의 알 수없는 상수를 문자열로 암시 적으로 변환하여 활용할 수 있다는 것입니다.
@$s=string;
이 @경고가 무시되도록해야합니다. 전반적으로 한 문자를 줄입니다.
때로는 자주 사용하는 함수의 이름으로 변수를 설정하는 것이 공간적으로 효과적 일 수 있습니다. 일반적으로 다음이있을 수 있습니다.
preg_match(..);preg_match(..);
그러나 골프를 타면 다음과 같이 쉽게 단축 할 수 있습니다.
@$p=preg_match;$p(..);$p(..);
"preg_match"인스턴스가 두 개만 있으면 단일 문자 만 저장하지만 함수를 많이 사용할수록 더 많은 공간을 절약 할 수 있습니다.
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와 혼동하지 마십시오).
중첩 함수 사용은 중첩 heredoc 내에서만 가능합니다 (또는 구문 분석 오류가 발생합니다)!
you will run into parse errors직접 읽을 수 없습니까? 성가신 젠드 엔진은 이것을 어떻게 결합 시키는가
!!$foo진실 값을 true(또는 1출력으로), 거짓 값 (0, 빈 문자열, 빈 배열)을 false(또는 빈 출력)으로 바꿉니다
. 코드 골프에서는 거의 필요하지 않습니다. 대부분의 경우 부울이 필요한 경우에는 어쨌든 암시 적 캐스트.
(int)$foo$foo|0또는 로 쓸 수 foo^0있지만 괄호가 필요할 수 있습니다.
부울 및 문자열의 경우 $foo*1또는 +$fooint로 캐스트하는 데 사용할 수 있습니다.
100을 추가 할 수 있습니다 *10.-> .0. 그러나이 경우 PHP는 점을 소수점으로 가져 가서 불평합니다. (문자열에 가변적 인 양의 0이 있으면 다릅니다.)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비트 단위와 (의 아스키 코드)의 문자에 수행 $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;
메모 +뿐만 아니라 인덱스 배열과 운영자 작업을하지만, 아마도 당신이 원하는 것을하지 않습니다.
+인덱스가 구별되는 한을 사용하여 숫자 형 배열을 병합 할 수도 있습니다 . 그렇지 않은 경우 첫 번째 배열의 값을 array_merge와 같이 두 번째 배열의 값으로 덮어 씁니다. 차이점 +은 인덱스를 재정렬하지 않습니다.
변수 변수 에 대한 몇 가지 흥미로운 사실
난 그냥 (I도 전에 공유했다 확인 중 적어도 하나는 골프를하는 데 도움이) :
$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_]변수 이름뿐만 아니라 모든 문자열에 사용할 수 있습니다 : $x="Hello!";$$x="Goodbye.";echo${"Hello!"};prints Goodbye..[a-zA-Z_][a-zA-Z_0-9]*변수 이름을 제외한 모든 것은 문자 그대로 사용하기 위해 중괄호가 필요합니다.$$x=1sets ${NULL}는 ${false}and와 동일합니다 ${""}. $a=1;$$a=5;뿐만 아니라 설정하지 ${1}뿐만 아니라 ${true}.
하나 더, 내가 지금까지 찾은 가장 이상한 것 : 시도 $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;}
화살표 기능-12 바이트- 온라인으로 사용해보십시오!
fn($n)=>$n+1
첫 번째 입력 항목 (int 배열)에 두 번째 입력 (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있습니까? 예, 그것은 화살표 기능 기능 중 하나입니다.
우리가 그들에게 이름을 줄 수 있기 때문에 변수의 폐쇄로 저장하는 것은 같은 보조 노트로서, 나는 (자체 내부의 같은 화살표 함수를 호출) 재귀 작업에 기능을 화살표 가져올 수 없습니다 $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)평소와 같이 전화하십시오 .
이 특별한 경우 double array_flip은 10 바이트를 절약합니다
($f=array_flip)($k=$f($c)))어레이의 모든 더블 값을 제거하고 난이 떨어졌다 $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
이 프로그램에서 버그를 발견하고 더 이상 double array_flip으로 교체 $x[$i]==$o?:$c[$x[$i]]=$o할 ($p=$x[$i])==$o?:$k[$c[$p]=$o]=$p필요가 없었습니다.
array_unique. 예이!
교차 문자열
join("DELIMITER",str_split($s))(31 바이트) 또는 심지어
preg_replace(".","DELIMITER",$s)(32 바이트)를 사용해 본 적이
있습니까?
거기에 내장되어 있습니다.
시도하십시오 chunk_split($s,1,"DELIMITER")(29 바이트).
세 번째 매개 변수를 생략하면 chunk_split사용합니다 \r\n; 7 또는 8 바이트를 절약 할 수 있습니다.
그러나주의 : chunk_split또한 문자열에 구분 기호를 추가
하므로 원하는 것을 정확하게 얻지 못할 수 있습니다.
(청크 길이를 제공하지 않으면 76을 사용합니다. 코드 골프에서는 드문 일이지만 누가 아는가)
strtr이 아이디어를 좋아하는 것과 함께 예제를 추가해야 할 수도 있습니다 .
경우에 따라 문자를 입력 할 수 있으며 각 문자마다 0보다 큰 입력을 반복하여 출력해야합니다.
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"truthy 인 -> 출력"a"
--$z=0; 그래서 우리는 설정 $c="b", $z="2"(그리고 $i=4) -> $c.$z="b2"입니다 truthy -> 출력"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;
여기서 •일반 결합 연산자를 나타냅니다. 이것은 일반적으로 바이트 수를 줄이지 만 창의력이 필요할 것입니다. $cond2처음부터 실패 할 수 있도록 작성해야합니다. $post1미리 실행하는 것이 더 쉬울 수 있지만 처음에는 실행에 실패해야합니다 $post1.
세 개 이상의 중첩 루프로 작업하는 경우 먼저 두 개를 결합한 다음 다른 루프를 결합 할 수 있습니다. 나는 내부에서 바깥쪽으로 결합하는 것이 일반적으로 더 쉽다는 것을 알았습니다.
예를 들어, 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()및 대신 부울 연산자를 사용하십시오.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 ^연산자는 결과를 짧은 입력 문자열의 길이로 자릅니다. 그래서 예를 들어,이 $W긴 입력 한 적어도 자리의 문자열이 $s다음 ~$W&$s에 상당 strtoupper($s)하고, $s|$W^$s동일하다 strtolower($s)(반면 $s|$W않는 공간 부가 된 문자열을 생성한다 자체 $s와 $W동일한 길이이다).
사용되지 않는 기능을 사용
하면 표현 사용에 5 개 이상의 바이트를 낭비하지 않고 대신 PERL 정규식의 POSIX를 사용할 수있는 경우 ereg나 eregi대신 preg_match, split나 spliti대신 preg_split의. 대부분의 구분 기호
split에 explode대한 동의어로 사용할 수도 있습니다 .
이 기능은 더 이상 사용되지 않는 것으로 표시되어 E_DEPRECATED알림을 표시 하지만 (지금 소스를 찾을 수 없음) 경고와 알림이 정상임을 읽은 것 같습니다.