回答:
それはあなたが知る必要がある最も重要なPerlゴルフのヒントです。タスクを達成するために絶対に必要な長すぎる文字のシーケンスを見ているときはいつでも、異なる機能を使用して同じ効果を得る他の方法がないかどうかを自問してください。通常あります。ここにほんの一握りがあります:
~~
はスカラーコンテキストを強制し、は4文字より短いですscalar
。
y///c
はlength
、の長さを取得するときよりも1文字短くなり$_
ます。
の文字を反復処理する必要があり$_
ますか?交換してくださいsplit//
と/./gs
。(または、/./g
改行もスキップしたい場合に使用します。)これは他の変数で機能します:replace split//,$x
で置き換え$x=~/./gs
ます。
すべてのPerlビルトインは何かを返します。print
たとえば、成功したI / Oを示すために1を返します。$_
たとえば、真の値に初期化する必要がある場合、$_=print$foo
1つの石で2羽の鳥を殺すことができます。
Perlのほとんどすべてのステートメントは式として記述できるため、さまざまなコンテキストで使用できます。複数のステートメントは、コンマで連結された複数の式になることができます。テストは?:
&&
||
、短絡演算子、およびand
and or
を使用して実行できます。これらは、同じことを行いますが、他のすべての演算子(割り当てを含む)よりも優先順位が低くなります。ループはmap
またはを介して実行できますgrep
。でも、キーワードのようにnext
、last
そしてreturn
、彼らは戻りませんが、表現コンテキストで使用することができます!この種の変換を念頭に置いておくと、コードブロックを、さまざまなコンテキストに詰め込むことができる式に置き換えることができます。
$foo
。それ以外の場合は、$_=1
よりもずっと短く$_=print""
、同じ効果があります。
$x
ですか?それ以外の場合は/./gs
、とすることができます/./g
。
Perlの特殊変数を乱用します!
前の回答で述べたように$/
して$"
にデフォルトで初期化され"\n"
そして" "
、それぞれ。
$,
そして、$\
の両方が設定されているundef
デフォルトでは、3つの文字短くなっています。
$\
値に設定すると、値がeveryに追加されますprint
。例:perl -ple '$\="=".hex.$/'
便利な16進数から10進数へのコンバーターです。
コマンドラインからファイルを読み取っていない場合は-i
、文字列を入力するための追加のチャネルとしてコマンドラインスイッチを使用できます。その値はに保存され$^I
ます。
$=
割り当てられたものはすべて強制的に整数になります。実行perl -ple '$_=$==$_'
してさまざまなinuptsを与えてみてください。同様に、$-
その値を強制的に負でない整数にします(つまり、先頭のダッシュは非数値文字として扱われます)。
ループの$.
繰り返しごとに真(ゼロ以外)の値に自動的にリセットされるブールフラグとして使用できwhile(<>)
ます。
-n
比類のない中括弧コマンドラインスイッチ-n
を使用して、1行ごとに1回スクリプトを実行できることはよく知られています。
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
と、入力のすべての行に対して実行した後に1回だけ出力され、その後にが続きmorecode
ます。
は実行$_
時に未定義であるためmorecode;print
、出力レコードのセパレータ$\
を悪用して実際の出力を印刷できます。
例えば
perl -pe '$\+=$_}{'
STDINから行ごとに1つの数値を読み取り、その合計を出力します。
#!perl -n
最初の行でこれを達成できると思いますよね?
$_
スカラー参照を排除するために使用します。ほとんどの関数でデフォルトとして使用されるのは特別な変数であり、パラメーターを省略するだけでこの変数を参照することができます。
変更することにより$n
に$_
、あなたは変更することができます$n=<>;chop$n;print$n
に$_=<>;chop;print
ここで、このprint
関数は$_
デフォルトでのコンテンツを印刷し、chop
でも動作し$_
ます。
$_=<>;
ていない、必要<>;
にラインを読んで$_
自動的に?
$_=<>;print
とを比較しました<>;print
。最初のものは私がタイプしたものを私に繰り返し返しますが、他のものはそうではありません。
print while(<>)
。それは特別なケースだか、その背後にあるいくつかのコヒーレントロジックがありますかどうかわから、どちらない<>
で一部のperlop
もwhile
の一部は、perlsyn
この動作を言及しているようです。
while(<>)
は、perlsyn、I / O Operatorsに文書化されている特殊なケースです。ループ)、値は自動的にグローバル変数$ _に割り当てられ、以前に存在していたものはすべて破壊されます。」
可能な限り、Perlの特殊変数を使用します。例:
$"
代わりに使用" "
$/
代わりに使用"\n"
字句解析器の助けを借りて、保証された1文字の長い識別子であるという追加の利点があります。これにより、次のように、それに続くキーワードに貼り付けることができます。print$.for@_
すべての特殊変数のリストは、ここから入手できます:特殊変数
使用しないでくださいqw
。これは、より良い方法で使用できる2つの文字の無駄です。たとえば、次のように書かないでください。
@i=qw(unique value);
代わりに、ベアワードを使用します。
@i=(unique,value);
または、ベアワードを使用できない場合は、glob
構文を使用します。
@i=<unique value>;
glob
構文は興味深い効果にも使用できます。
@i=<item{1,2,3}>;
しないでください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){}
対 map{}@c;
またfor
、map
。内にpostfix ループを配置できるため、ネストされた反復を実行する場合に便利です。
Perlには「一致する前のテキスト」と「一致した後のテキスト」のマジック変数があるため、潜在的に少ない文字で2つのグループに分割できます。
($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
コードでsayを4回以上呼び出す場合(これは呼び出しているルーチンの長さによって明らかに異なります)、短いサブ名に置き換えてください:
sub p{print@_}p;p;p;p
対
print;print;print;print
次のようなコードがある場合:
$i--if$i>0
次を使用できます:
$i-=$i>0
代わりに、いくつかのバイトを保存します。
変数に割り当てていないため、ブレッドボックスのヒントを使用できない場合は、次の式を使用できます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
redo
ブロックにすることなく、ループ動作が追加されますfor
かwhile
。 {redo}
無限ループです。
ネストされた3項論理内で複数の異なるステートメントを実行できます。
大きな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
単に変数を出力するだけです。最後の1つは、特にこのチャレンジにのみ適用されます(19バイト):
print int(rand(10))
ただし、これは、代入と出力の間に変数に対して何もする必要がない場合にのみ機能します。
これの適切な例は、入力を正弦波に整形する次のコードです。
s/./print" "x(sin($i+=.5)*5+5).$&/eg;
ご覧のとおり、標準入力の文字を反復処理する非常にコンパクトな方法です。他の正規表現を使用して、一致する方法を変更できます。
$_=print""
はより短いです$_=print$foo
。