답변:
이것이 가장 중요한 Perl 골프 팁입니다. 작업을 수행하기 위해 너무 긴 문자 시퀀스를 볼 때마다 다른 기능을 사용하여 동일한 효과를 얻을 수있는 다른 방법이 없는지 자문 해보십시오. 보통 있습니다. 다음은 소수입니다.
~~
스칼라 컨텍스트를 적용하고보다 짧은 4 자 scalar
입니다.
y///c
length
의 길이를 가져올 때보 다 한 문자가 짧습니다 $_
.
의 문자를 반복해야 $_
합니까? 교체 split//
와 함께 /./gs
. (또는 사용 /./g
당신은 또한 줄 바꿈을 건너 뛰십시오.) 다른 변수와이 작품 : 교체 split//,$x
와 함께 $x=~/./gs
.
모든 Perl 내장은 무언가를 반환합니다. print
예를 들어 성공적인 I / O를 나타 내기 위해 1을 반환합니다. $_
예를 들어, 실제 값 으로 초기화해야하는 경우 $_=print$foo
하나의 돌로 두 마리의 새를 죽일 수 있습니다.
Perl의 거의 모든 문장은 표현식으로 작성되어보다 다양한 상황에서 사용될 수 있습니다. 여러 명령문은 쉼표로 묶인 여러 표현식이 될 수 있습니다. 시험은 단락 운영자 수행 할 수 있습니다 ?:
&&
||
, 또한으로 and
하고 or
, 같은 일을하는 그러나 우선 순위가 (할당 포함) 모든 다른 연산자보다 낮 춥니 다. 루프를 통해 수행 할 수 있습니다 map
또는 grep
. 심지어 키워드와 같은 next
, last
그리고 return
그들이 반환하지 않더라도, 표현 컨텍스트에서 사용할 수 있습니다! 이러한 종류의 변환을 염두에두면 코드 블록을보다 다양한 컨텍스트에 채워질 수있는 표현식으로 대체 할 수 있습니다.
$foo
입니다. 그렇지 않으면, $_=1
훨씬 짧고 $_=print""
같은 효과가 있습니다.
$x
입니까? 그렇지 않으면 당신은 할 수 /./gs
와 /./g
.
펄의 특수 변수 남용!
이전 답변에서 언급 한 바와 같이 $/
그리고 $"
기본적으로 초기화 "\n"
하고 " "
각각.
$,
그리고 $\
으로 설정되어 undef
기본적으로 3 개 문자 짧다.
값 $\
을 설정 하면 모든에 추가됩니다 print
. 예를 들면 다음과 같습니다 perl -ple '$\="=".hex.$/'
. 편리한 16 진수 변환기입니다.
명령 줄에서 파일을 읽지 않는 경우 -i
명령 줄 스위치를 문자열 입력을위한 추가 채널로 사용할 수 있습니다 . 그 값은에 저장됩니다 $^I
.
$=
할당 된 모든 것을 정수로 만듭니다. 달리고 perl -ple '$_=$==$_'
다양한 종류의 inupts를 제공하십시오. 마찬가지로, $-
값을 음이 아닌 정수로 만듭니다 (즉, 선행 대시는 숫자가 아닌 문자로 처리됨).
루프를 $.
반복 할 때마다 0이 아닌 값으로 자동 재설정되는 부울 플래그로 사용할 수 있습니다 while(<>)
.
-n
타의 추종을 불허하는 중괄호명령 행 스위치 -n
를 사용하여 모든 행에 대해 스크립트를 한 번 실행할 수 있습니다.
perl --help
말한다 :
-n assume "while (<>) { ... }" loop around program
명시 적으로 말하지 않은 것은 Perl이 단지 프로그램 주위의 루프를 가정하지 않는다는 것입니다. 그것은 말 그대로 랩 while (<>) { ... }
주위.
이런 식으로 다음 명령은 서로 동일합니다.
perl -e 'while(<>){code}morecode'
perl -ne 'code;END{morecode}'
perl -ne 'code}{morecode'
-p
타의 추종을 불허하는 중괄호위와 마찬가지로 -p
스위치가 while (<>) { ... ; print }
프로그램을 둘러 쌉니다 .
일치하지 않는 중괄호를 사용 perl -p 'code}{morecode'
하면 code
모든 입력 행에 대해 실행 한 후 한 번만 인쇄 한 다음에 morecode
.
가 실행될 $_
때 undefined 이므로 morecode;print
출력 레코드 구분 기호 $\
가 남용되어 실제 출력을 인쇄 할 수 있습니다.
예를 들어
perl -pe '$\+=$_}{'
STDIN에서 한 줄에 하나의 숫자를 읽고 합계를 인쇄합니다.
#!perl -n
첫 번째 줄 에서이 작업을 수행 할 수 있다고 가정합니다 .
}for(...){
중괄호 사이에 종종뿐만 아니라, 예를 들면 매우 편리 codegolf.stackexchange.com/a/25632
$_
스칼라 참조를 제거하는 데 사용하십시오 . 대부분의 함수에서 기본값으로 사용되는 특수 변수이며 매개 변수를 생략하면이 변수를 참조 할 수 있습니다.
로 변경 $n
하면 $_
다음으로 변경할 수 있습니다 $n=<>;chop$n;print$n
.$_=<>;chop;print
이 print
함수는 $_
기본적으로 내용을 인쇄하고에서 chop
작동합니다 $_
.
$_=<>;
하지 않고, 필요 <>;
로 라인을 읽어 $_
자동으로?
$_=<>;print
하고 <>;print
. 첫 번째는 내가 입력 한 내용을 다시 반복하지만 다른 하나는 입력하지 않습니다.
print while(<>)
. 확실하지, 어느 쪽이 특별한 경우 나 일부 일관된 논리가 배후에있을 경우 <>
의에 참여 perlop
도 while
의 일부가 perlsyn
이 문제를 언급하는 것 같다.
while(<>)
는 perlsyn, I / O Operators에 설명 된 특수한 경우입니다. loop), 값이 자동으로 전역 변수 $ _에 할당되어 이전에 있던 것을 파괴합니다. "
가능한 한 Perl의 특수 변수를 사용하십시오. 예 :
$"
대신 사용" "
$/
대신 사용"\n"
그들은 어휘 분석기의 도움으로 보장 된 1 문자 길이의 식별자라는 추가적인 이점을 가지고 있습니다. 이렇게하면 다음과 같이 다음 키워드에 붙일 수 있습니다.print$.for@_
모든 특수 변수 목록은 여기에서 확인할 수 있습니다 : 특수 변수
하지 마십시오 use strict
. (PCG.SE 컨텍스트에 대해 인용하지 마십시오.) 더 중요한 것은 엄격한 조건 에서처럼 코딩하지 마십시오. 일반적인 용의자 :
my
피할 수 있다면 변수를 선언 하지 마십시오 . 실제로 필요한 유일한 변수는 my
어휘 범위를 원하는 변수입니다 . 스코프 보호가 필요하지 않고 재귀를 완전히 제어하는 경향이있는 골프를 타는 경우는 거의 없습니다.print hello
작동하지 않습니다. 실제로는 print hello $_
( $_
filehandle로 인쇄) 를 의미 hello
합니다.
print
지금은 훌륭하고 짧은 예를 찾을 수 없다)
나는 이것들 중 일부가 공식적인 이름을 가지고 있다고 확신하며 그것들을 알지 못합니다.
print $n++ while ($n < 10)
$var = join('',<>)
print ('X'*10) . "\n";
이상입니다print ('X'*10) . $/;
say
기능은보다 짧지 만 대신 print
코드를 실행해야합니다.-E
-e
a..z
또는 같은 범위를 사용하십시오 aa..zz
. 문자열로 필요한 경우을 사용하십시오 join
.$z = 'z'; print ++$z;
표시aa
그것이 내가 지금 생각할 수있는 전부입니다. 나중에 더 추가 할 수 있습니다.
print ('X'*10) . $/;
어떻게해야? 나를 위해 그것은 인쇄 0
하고 줄 바꿈이 없습니다. 우선, 괄호는에 대한 함수 스타일 호출 인수가되어 print
보다 꽉 묶습니다 .
. 그리고 x
대신 *
또는 무언가 를 의미 했 습니까?
while
, join'',<>;
또한 그들없이 작동합니다.
사용 $%
대신하는 것은 $a
당신이 바로 옆에 변수 이름을 배치하도록 할 수 있습니다 if
, for
또는 while
같이 구성 :
@r=(1,2,3,4,5);$%=4;
print$_*$%for@r
많은 것을 사용할 수 있지만 어떤 마법 효과가 있는지에 대한 문서 와 @BreadBox의 답변 을 확인하십시오 !
@JB 의 답변에 따라 명령문 수정자를 사용할 수 없으면 map이 바이트를 저장할 수 있습니다.
for(@c){}
vs. map{}@c;
postfix for
루프를 안에 넣을 수 있으므로 중첩 반복을 수행하려는 경우 유용 합니다 map
.
Perl은 'text before match'와 'match after text'에 대한 마법 변수를 가지고 있으므로 잠재적으로 더 적은 문자로 두 그룹으로 나눌 수 있습니다.
($x,$y)=split/,/,$_;
($x,$y)=/(.+),(.+)/;
/,/; # $x=$`, $y=$'
# Note: you will need to save the variables if you'll be using more regex matches!
이것은 다음의 대체물로도 잘 작동 할 수 있습니다 substr
.
$s=substr$_,1;
/./;# $s=$'
$s=substr$_,4;
/.{4}/;# $s=$'
일치하는 내용이 필요한 경우 다음과 $&
같이 사용할 수 있습니다.
# assume input like '10 PRINT "Hello, World!"'
($n,$c,$x)=split/ /,$_;
/ .+ /; # $n=$`, $c=$&, $x=$'
print
코드에서 네 번 이상 호출하면 (이것은 분명히 호출하는 루틴의 길이에 따라 다름) 더 짧은 하위 이름으로 바꾸십시오.
sub p{print@_}p;p;p;p
vs.
print;print;print;print
다음과 같은 코드가있는 경우 :
$i--if$i>0
당신이 사용할 수있는:
$i-=$i>0
대신 일부 바이트를 저장하십시오.
변수에 할당하지 않고 breadbox의 팁을 사용할 수없는 경우 표현식을 사용할 수 있습니다 0|
.
rand 25 # random float eg. 19.3560355885212
int rand 25 # random int
0|rand 25 # random int
rand 25|0 # random int
~~rand 25 # random int
그러나 배열 인덱스에 액세스하기 위해 정수를 사용할 필요가없는 것보다 주목할 가치가 있습니다.
@letters = A..Z;
$letters[rand 26]; # random letter
중첩 된 삼항 논리 내에서 여러 개의 다른 명령문을 실행할 수 있습니다.
당신은 큰 있다고 가정 if
- elsif
문을. 이것은 어떤 논리 나 여러 문장 일 수 있습니다.
if( $_ < 1 ) {
$a=1;
$b=2;
$c=3;
say $a.$b.$c;
} elsif($_ < 2 ) {
$a=3;
$b=2;
$c=1;
say $a.$b.$c;
} elsif( $_ < 3) {
$a=2;
$b=2;
$c=2;
say $a.$b.$c;
}
(cmd1, cmd2, cmd3)
삼항 연산자 내부 를 사용 하여 모든 명령을 실행할 수 있습니다 .
$_ < 1 ?
($a=1,$b=2,$c=3,say$a.$b.$c):
$_ < 2 ?
($a=3,$b=2,$c=1,say$a.$b.$c):
$_ < 3 ?
($a=2,$b=2,$c=2,say$a.$b.$c):
0; #put the else here if we have one
더미 예제는 다음과 같습니다.
perl -nE'$_<1?($a=1,$b=2,$c=3,say$a.$b.$c):$_<2?($a=3,$b=2,$c=1,say$a.$b.$c):$_<3?($a=2,$b=2,$c=2,say$a.$b.$c):0;' <(echo 2)
select(undef,undef,undef,$timeout)
대신 사용Time::HiRes
( https://stackoverflow.com/a/896928/4739548 에서 가져옴 )
많은 문제는 정수보다 더 높은 정밀도로 수면을 취해야합니다. select()
의 타임 아웃 인수가 바로 그렇게 할 수 있습니다.
select($u,$u,$u,0.1)
다음보다 훨씬 효율적입니다.
import Time::HiRes qw(sleep);sleep(0.1)
전자는 20 바이트에 불과하고 후자는 39 바이트를 차지합니다. 그러나 전자는 사용 $u
하고 있지 않으며이를 정의한 적이 없습니다.
그것을 많이 사용하려고한다면 수입이 많이 발생 Time::HiRes
하지만 한 번만 필요 select($u,$u,$u,0.1)
하면 19 바이트 를 절약하면 대부분의 경우 확실히 향상됩니다.
챌린지가 달리 명시하지 않는 한, 줄 바꿈이 필요하지 않습니다.
우리의 '도전'은 '0에서 9까지의 난수를 STDOUT에 출력합니다'라고 말합니다. 이 코드 (28 바이트)를 사용할 수 있습니다.
$s=int(rand(10));print"$s\n"
그리고 이것을 이것을 25 바이트로 줄이십시오 :
$s=int(rand(10));print $s
단순히 변수를 인쇄하여. 이 마지막 것은이 도전에 구체적으로 만 적용됩니다 (19 바이트).
print int(rand(10))
그러나 할당과 인쇄 사이에 변수에 대해 아무것도 할 필요가 없을 때만 작동합니다.
이에 대한 적절한 설명은 입력을 사인파로 형성하는 코드입니다.
s/./print" "x(sin($i+=.5)*5+5).$&/eg;
보시다시피 표준 입력에서 문자를 반복하는 매우 간단한 방법입니다. 다른 정규식을 사용하여 일치하는 방식을 변경할 수 있습니다.
$_=print""
보다 짧습니다$_=print$foo
.