Jawaban:
Itulah tip golfing Perl yang paling penting yang perlu Anda ketahui. Setiap kali Anda melihat urutan karakter terlalu lama yang harus Anda miliki untuk menyelesaikan tugas, tanyakan pada diri sendiri apakah tidak ada cara lain untuk mendapatkan efek yang sama menggunakan fitur yang berbeda. Biasanya ada. Ini hanya beberapa:
~~
menegakkan konteks skalar dan 4 karakter lebih pendek dari scalar
.
y///c
adalah satu char lebih pendek dari length
ketika mendapatkan panjang $_
.
Perlu mengulangi karakternya $_
? Ganti split//
dengan /./gs
. (Atau gunakan /./g
jika Anda juga ingin melewatkan baris baru.) Ini berfungsi dengan variabel lain: ganti split//,$x
dengan $x=~/./gs
.
Setiap Perl dibangun mengembalikan sesuatu. print
mengembalikan 1, misalnya, untuk menunjukkan I / O berhasil. Jika Anda perlu menginisialisasi $_
ke nilai sebenarnya, misalnya, $_=print$foo
memungkinkan Anda untuk membunuh dua burung dengan satu batu.
Hampir setiap pernyataan dalam Perl dapat ditulis sebagai ekspresi, yang memungkinkannya untuk digunakan dalam berbagai konteks yang lebih luas. Beberapa pernyataan dapat menjadi beberapa ekspresi yang dirangkai bersama dengan koma. Pengujian dapat dilakukan dengan operator hubungan arus pendek ?:
&&
||
, dan juga dengan and
dan or
, yang melakukan hal yang sama tetapi dengan diutamakan lebih rendah dari semua operator lain (termasuk penugasan). Loop dapat dilakukan melalui map
atau grep
. Bahkan kata kunci suka next
, last
dan return
dapat digunakan dalam konteks ekspresi, meskipun tidak kembali! Mempertahankan transformasi semacam ini dalam pikiran memberi Anda peluang untuk mengganti blok kode dengan ekspresi yang dapat dimasukkan ke dalam berbagai konteks yang lebih luas.
$foo
. Kalau tidak, $_=1
jauh lebih pendek daripada $_=print""
dan memiliki efek yang sama.
$x
? Kalau tidak, Anda hanya bisa melakukan /./gs
dan /./g
.
Variabel khusus penyalahgunaan Perl!
Seperti disebutkan dalam jawaban sebelumnya $/
dan $"
diinisialisasi secara default untuk "\n"
dan " "
, masing-masing.
$,
dan $\
keduanya diatur undef
secara default, dan 3 karakter lebih pendek.
Pengaturan $\
ke nilai akan menyebabkannya ditambahkan ke setiap print
. Sebagai contoh: perl -ple '$\="=".hex.$/'
adalah konverter hex-to-desimal berguna.
Jika Anda tidak membaca file dari baris perintah, Anda dapat menggunakan -i
saklar baris perintah sebagai saluran tambahan untuk memasukkan string. Nilainya akan disimpan di $^I
.
$=
memaksa apa pun yang ditugaskan padanya untuk menjadi bilangan bulat. Coba jalankan perl -ple '$_=$==$_'
dan berikan berbagai inupts. Demikian juga, $-
memaksa nilainya menjadi bilangan bulat non-negatif (yaitu tanda hubung utama diperlakukan sebagai karakter non-numerik).
Anda dapat menggunakan $.
sebagai boolean flag yang secara otomatis di-reset ke nilai true (bukan nol) pada setiap iterasi while(<>)
loop.
-n
dan kurung keriting yang tak tertandingiDiketahui bahwa saklar baris perintah -n
dapat digunakan untuk mengeksekusi skrip sekali untuk setiap baris.
perl --help
mengatakan:
-n assume "while (<>) { ... }" loop around program
Apa yang tidak dikatakannya secara eksplisit adalah bahwa Perl tidak hanya mengasumsikan loop di sekitar program; itu benar - benar membungkusnya while (<>) { ... }
.
Dengan cara ini, perintah berikut ini setara satu sama lain:
perl -e 'while(<>){code}morecode'
perl -ne 'code;END{morecode}'
perl -ne 'code}{morecode'
-p
dan kurung keriting yang tak tertandingiDemikian pula dengan yang di atas, -p
saklar membungkus while (<>) { ... ; print }
program.
Dengan menggunakan kurung keriting yang tidak tertandingi, perl -p 'code}{morecode'
hanya akan mencetak sekali setelah mengeksekusi code
untuk semua jalur input, diikuti oleh morecode
.
Karena $_
tidak ditentukan saat morecode;print
dieksekusi, pemisah catatan output $\
dapat disalahgunakan untuk mencetak output yang sebenarnya.
Sebagai contoh
perl -pe '$\+=$_}{'
membaca satu nomor per baris dari STDIN dan mencetak jumlahnya.
#!perl -n
di baris pertama, kan?
}for(...){
di sela-sela kawat gigi seringkali cukup berguna juga, misalnya codegolf.stackexchange.com/a/25632
Gunakan $_
untuk menghilangkan referensi skalar. Ini adalah variabel khusus yang digunakan sebagai default oleh sebagian besar fungsi, dan hanya menyisakan parameter adalah jalan pintas untuk referensi variabel ini.
Dengan mengubah $n
ke $_
, Anda dapat mengubah $n=<>;chop$n;print$n
ke$_=<>;chop;print
Di sini, print
fungsi mencetak konten $_
secara default, dan chop
juga berfungsi $_
.
$_=<>;
wajib, tidak <>;
membaca baris ke $_
otomatis?
$_=<>;print
dan <>;print
. Yang pertama mengulangi kembali kepada saya apa yang saya ketik, sedangkan yang lain tidak.
print while(<>)
. Tidak yakin apakah ini kasus khusus atau ada beberapa logika yang koheren di belakangnya, tidak ada <>
bagian perlop
atau pun while
bagian yang perlsyn
menyebutkan perilaku ini.
while(<>)
adalah kasus khusus, didokumentasikan dalam perlsyn, I / O Operator: 'Jika dan hanya jika simbol input adalah satu-satunya hal di dalam syarat pernyataan "sementara" (bahkan jika disamarkan sebagai "untuk (;;)" loop), nilai tersebut secara otomatis ditetapkan ke variabel global $ _, menghancurkan apa pun yang ada sebelumnya. "
Gunakan variabel khusus Perl kapan pun Anda bisa, misalnya:
$"
sebagai ganti" "
$/
sebagai ganti"\n"
Mereka memiliki manfaat tambahan sebagai pengidentifikasi panjang satu karakter yang dijamin, dengan bantuan dari lexer. Ini memungkinkan untuk merekatkannya ke kata kunci yang mengikutinya, seperti pada:print$.for@_
Daftar semua variabel khusus tersedia di sini: Variabel Khusus
Jangan gunakan qw
. Ini adalah pemborosan dari dua karakter yang dapat digunakan dengan cara yang lebih baik. Misalnya, jangan menulis yang berikut ini.
@i=qw(unique value);
Alih-alih menggunakan kata kunci.
@i=(unique,value);
Atau jika Anda tidak dapat menggunakan kata kunci, gunakan glob
sintaks.
@i=<unique value>;
glob
sintaksis juga dapat digunakan untuk efek yang menarik.
@i=<item{1,2,3}>;
Gunakan pengubah pernyataan alih-alih pernyataan majemuk.
Pernyataan majemuk cenderung membutuhkan tanda kurung untuk argumen dan kurung untuk blok, sedangkan pengubah pernyataan tidak membutuhkan keduanya.
Membandingkan:
$a++,$b++while$n--
vs. while($n--){$a++;$b++}
chop$,if$c
vs. if($c){chop$,}
Perhatikan bahwa contoh terakhir ada hubungannya $c&&chop$,
, tetapi mulai benar-benar bersinar untuk sebagian besar operasi multi-pernyataan. Pada dasarnya apa pun yang kehilangan prioritas operator &&
.
Jangan use strict
. (jangan mengutip saya tentang ini, konteks PCG.SE agak penting) Dan, yang lebih penting, jangan kode seolah-olah di bawah ketat. Tersangka yang biasa:
my
-deklarasikan variabel jika Anda bisa menghindarinya. Satu-satunya variabel yang benar-benar dibutuhkan my
adalah yang Anda inginkan dicakup secara leksikal. Itu hampir tidak ada dari mereka ketika bermain golf, di mana Anda tidak membutuhkan perlindungan ruang lingkup dan cenderung untuk sepenuhnya mengendalikan rekursi.print hello
tidak akan bekerja Ini sebenarnya berarti print hello $_
(cetak $_
ke filehandle hello
).
print
, dan sekarang saya tidak dapat menemukan contoh yang bagus dan pendek)
Saya yakin beberapa di antaranya memiliki nama resmi dan saya tidak menyadarinya.
print $n++ while ($n < 10)
$var = join('',<>)
print ('X'*10) . "\n";
lebih lama daripadaprint ('X'*10) . $/;
say
Fungsi Perl lebih pendek daripada print
, tetapi Anda harus menjalankan kode dengan -E
alih - alih-e
a..z
atau bahkan aa..zz
. Jika diperlukan sebagai string, gunakan join
.$z = 'z'; print ++$z;
akan ditampilkanaa
Hanya itu yang bisa saya pikirkan saat ini. Saya dapat menambahkan lagi nanti.
print ('X'*10) . $/;
seharusnya dilakukan? Bagi saya itu mencetak 0
dan tidak ada baris baru. Untuk satu hal, tanda kurung menjadi argumen panggilan fungsi-gaya print
, yang mengikat lebih ketat dari .
. Dan apakah yang Anda maksudkan x
bukan *
atau sesuatu?
while
, join'',<>;
juga berfungsi tanpa tanda kurung .
Menggunakan $%
alih-alih $a
dapat memungkinkan Anda untuk menempatkan nama variabel tepat di sebelah if
, for
atau while
membuat seperti pada:
@r=(1,2,3,4,5);$%=4;
print$_*$%for@r
Banyak yang dapat digunakan, tetapi periksa dokumen dan jawaban @ BreadBox yang mana yang memiliki efek ajaib!
Jika Anda tidak dapat menggunakan pengubah pernyataan sesuai jawaban @ JB , peta mungkin menyimpan byte:
for(@c){}
vs. map{}@c;
dan berguna jika Anda ingin melakukan iterasi bersarang karena Anda dapat menempatkan for
loop postfix di dalam map
.
Perl memiliki variabel ajaib untuk 'teks sebelum pertandingan' dan 'teks setelah pertandingan' sehingga dimungkinkan untuk dipecah menjadi kelompok dua dengan karakter yang berpotensi lebih sedikit:
($x,$y)=split/,/,$_;
($x,$y)=/(.+),(.+)/;
/,/; # $x=$`, $y=$'
# Note: you will need to save the variables if you'll be using more regex matches!
Ini juga bisa berfungsi sebagai pengganti untuk substr
:
$s=substr$_,1;
/./;# $s=$'
$s=substr$_,4;
/.{4}/;# $s=$'
Jika Anda membutuhkan konten pertandingan, $&
dapat digunakan, misalnya:
# assume input like '10 PRINT "Hello, World!"'
($n,$c,$x)=split/ /,$_;
/ .+ /; # $n=$`, $c=$&, $x=$'
Jika Anda menelpon katakan print
empat kali atau lebih dalam kode Anda (ini jelas berbeda dengan panjang rutin yang Anda panggil), gantilah dengan sub nama yang lebih pendek:
sub p{print@_}p;p;p;p
vs.
print;print;print;print
Jika Anda memiliki kode seperti:
$i--if$i>0
Anda dapat gunakan:
$i-=$i>0
alih-alih menyimpan beberapa byte.
Jika Anda tidak menetapkan ke variabel dan tidak bisa menggunakan tip kotak roti , Anda bisa menggunakan ekspresi 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
Namun perlu dicatat daripada Anda tidak perlu menggunakan integer untuk mengakses indeks array:
@letters = A..Z;
$letters[rand 26]; # random letter
redo
menambahkan perilaku loop ke blok tanpa for
atau while
. {redo}
adalah loop tak terbatas.
Jangan kurung panggilan fungsi.
Perl memungkinkan Anda memanggil fungsi yang dikenal (inti atau yang telah dideklarasikan) menggunakan NAME LIST
sintaks. Ini memungkinkan Anda menjatuhkan &
sigil (jika Anda masih menggunakannya) serta tanda kurung.
Sebagai contoh: $v=join'',<>
Cobalah untuk menggunakan nilai ekspresi penugasan, seperti:
# 14 characters
$n=pop;$o=$n&1
# 13 characters, saves 1
$o=($n=pop)&1
Ini berfungsi karena $n
2 karakter dalam Perl. Anda dapat mengubah $n
ke ()
tanpa biaya, dan menghemat 1 titik koma dengan memindahkan tugas ke dalam tanda kurung.
Anda dapat menjalankan beberapa pernyataan berbeda dalam logika terner bersarang.
Misalkan Anda memiliki besar if
- elsif
pernyataan. Ini bisa berupa logika dan sejumlah pernyataan.
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;
}
Anda dapat menggunakan (cmd1, cmd2, cmd3)
di dalam operator ternary untuk menjalankan semua perintah.
$_ < 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
Berikut ini contoh tiruannya:
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)
sebagai gantiTime::HiRes
(Diambil dari https://stackoverflow.com/a/896928/4739548 )
Banyak tantangan yang mengharuskan Anda tidur dengan presisi lebih tinggi daripada bilangan bulat. select()
Argumen batas waktu dapat melakukan hal itu.
select($u,$u,$u,0.1)
jauh lebih efisien daripada:
import Time::HiRes qw(sleep);sleep(0.1)
Yang pertama hanya 20 byte, sedangkan yang terakhir memakan waktu 39. Namun, yang pertama mengharuskan Anda tidak menggunakan $u
dan tidak pernah mendefinisikannya.
Jika Anda akan menggunakannya, banyak yang diimportensikan Time::HiRes
terbayar, tetapi jika Anda hanya membutuhkannya sekali saja, menggunakan select($u,$u,$u,0.1)
simpanan 19 byte, yang jelas merupakan peningkatan dalam banyak kasus.
Kecuali jika tantangannya menentukan sebaliknya, Anda tidak perlu membuntuti baris baru.
'Tantangan' kami mengatakan 'mengeluarkan angka acak dari 0 hingga 9 ke STDOUT'. Kita dapat mengambil kode ini (28 byte):
$s=int(rand(10));print"$s\n"
Dan persingkat menjadi ini (25 byte):
$s=int(rand(10));print $s
hanya dengan mencetak variabel. Yang terakhir ini hanya berlaku untuk tantangan ini secara khusus (19 byte):
print int(rand(10))
tetapi itu hanya berfungsi ketika Anda tidak perlu melakukan apa pun pada variabel di antara tugas dan pencetakan.
Kadang-kadang (sering ketika berhadapan dengan tantangan quine atau sumber terbatas ) Anda mendapat manfaat besar dari kemampuan untuk bersarang string literal. Biasanya, Anda akan melakukan ini dengan q(…)
. Namun, tergantung pada karakter apa yang Anda butuhkan di dalam string, Anda mungkin dapat menyimpan byte dan menggunakan <…>
, operator glob. (Perhatikan bahwa apa yang ada di dalam kurung sudut tidak dapat terlihat seperti filehandle, dan tidak terlihat seperti itu dimaksudkan untuk diperluas menjadi daftar nama file, yang berarti bahwa cukup banyak karakter tidak akan berfungsi dengan benar.)
Ilustrasi yang layak untuk hal ini adalah kode berikut yang membentuk input menjadi gelombang sinus:
s/./print" "x(sin($i+=.5)*5+5).$&/eg;
Seperti yang Anda lihat, ini cara yang ringkas untuk mengulangi karakter dalam input standar. Anda bisa menggunakan regex lain untuk mengubah cara semuanya dicocokkan.
$_=print""
lebih pendek dari$_=print$foo
.