Yanıtlar:
Bilmeniz gereken en önemli Perl golf ipucu. Çok uzun bir dizi karaktere baktığınızda, görevinizi tamamlamak için mutlaka yapmanız gereken, farklı bir özellik kullanarak aynı etkiyi elde etmenin başka bir yolu olmadığını kendinize sorun. Genellikle var. İşte sadece bir avuç:
~~
bir skalar bağlamı zorlar ve 4 karakterden kısa scalar
.
y///c
length
uzunluğu elde edilenden daha kısa bir karakter $_
.
İçindeki karakterleri yinelemeye $_
mi ihtiyacınız var ? Değiştir split//
ile /./gs
. (Ya kullanımı /./g
da yeni satır atlamak istiyorum.) Diğer değişkenlerle Bu eserler: yerine split//,$x
ile $x=~/./gs
.
Her Perl yerleşik bir şey döndürür. print
başarılı G / Ç'yi belirtmek için örneğin 1 değerini döndürür. $_
Örneğin, gerçek bir değere sıfırlamanız gerekirse, $_=print$foo
iki kuşu bir taşla öldürmenize izin verir.
Perl'deki hemen hemen her ifade, daha geniş bir bağlamda kullanılmasına izin vererek bir ifade olarak yazılabilir. Çoklu ifadeler, virgüllerle birlikte zincirlenmiş çoklu ifadeler haline gelebilir. Testler kısa devre yapan operatörlerle ?:
&&
||
ve aynı zamanda and
ve or
aynı şeyi yapan ancak önceliği diğer tüm operatörlerden daha düşük olan (atama dahil) yapılabilir. Döngüler üzerinden yapılabilecek map
ya grep
. Hatta anahtar kelimeler gibi next
, last
ve return
onlar dönmek yok olsa bile, bir ifade bağlamında kullanılabilir! Bu tür dönüşümlerin akılda tutulması size, kod bloklarını daha geniş bir bağlamda girebilecek ifadelerle değiştirme fırsatını verir.
$foo
. Aksi takdirde, aynı etkiye $_=1
göre çok daha kısa $_=print""
ve daha kısadır .
$x
? Aksi takdirde sadece /./gs
ve yapabilirdi /./g
.
Kötüye Perl'in özel değişkenleri!
Bir önceki yanıtta belirtildiği gibi $/
ve $"
varsayılan olarak başlatılır "\n"
ve " "
sırasıyla.
$,
ve $\
her ikisi de undef
varsayılan olarak ayarlanmıştır ve 3 karakter daha kısadır.
$\
Bir değere ayarlamak , her birine eklenmesine neden olacaktır print
. Örneğin: perl -ple '$\="=".hex.$/'
kullanışlı bir hex-ondalık dönüştürücü.
Dosyaları komut satırından okuyamıyorsanız, -i
komut satırı anahtarını dize girmek için fazladan bir kanal olarak kullanabilirsiniz . Değeri depolanacaktır $^I
.
$=
kendisine verilenleri bir tamsayı olarak zorlar. Çalıştırmayı deneyin perl -ple '$_=$==$_'
ve ona çeşitli inupts vererek. Benzer şekilde, $-
değerini negatif olmayan bir tamsayı olmaya zorlar (yani, öncü bir çizgi sayısal olmayan bir karakter olarak değerlendirilir).
$.
Bir while(<>)
döngünün her yinelemesinde otomatik olarak gerçek (sıfır olmayan) bir değere sıfırlanan bir boolean bayrağı olarak kullanabilirsiniz .
-n
ve eşsiz kıvrımlı parantezKomut satırı anahtarının -n
komut dosyasını her satır için bir kez çalıştırmak için kullanılabileceği iyi bilinmektedir .
perl --help
diyor:
-n assume "while (<>) { ... }" loop around program
Açıkça söylemediği şey, Perl’in sadece program etrafında bir döngü üstlenmemesi; o anlamıyla sarar while (<>) { ... }
etrafında.
Bu şekilde, aşağıdaki komutlar birbirine eşdeğerdir:
perl -e 'while(<>){code}morecode'
perl -ne 'code;END{morecode}'
perl -ne 'code}{morecode'
-p
ve eşsiz kıvrımlı parantezYukarıdakilere benzer şekilde, -p
anahtar while (<>) { ... ; print }
programın etrafına sarılır .
Eşsiz küme parantezleri kullanıldığında, tüm girdi satırları için perl -p 'code}{morecode'
yürütüldükten sonra sadece bir kez basılır code
, ardından gelir morecode
.
Yana $_
zaman tanımlanmamış morecode;print
yürütüldüğünde, çıkış kayıt ayırıcı $\
gerçek çıktı yazdırmak için kötüye kullanılabilir.
Örneğin
perl -pe '$\+=$_}{'
STDIN'den satır başına bir sayı okur ve toplamını yazdırır.
#!perl -n
ilk satırda başarabileceğini sanıyorum , değil mi?
}for(...){
destekler arasında genellikle de, örneğin oldukça kullanışlı codegolf.stackexchange.com/a/25632
$_
Skaler referansları ortadan kaldırmak için kullanın . Çoğu işlev tarafından varsayılan olarak kullanılan özel değişkendir ve sadece parametreleri dışarıda bırakmak, bu değişkeni referans almak için bir kısayoldur.
Değiştirerek $n
etmek $_
, değiştirmek olabilir $n=<>;chop$n;print$n
için$_=<>;chop;print
Burada, print
işlev $_
varsayılan olarak içeriğini yazdırır ve üzerinde chop
de çalışır $_
.
$_=<>;
gelmez, gerekli <>;
konusunda çizgiyi okumak $_
otomatik?
$_=<>;print
ve <>;print
. İlki yazdığım şeyi bana geri veriyor, diğeri yazmıyor.
print while(<>)
. Emin değilim, ne de özel bir durum ya da bazı tutarlı bir mantık bunun arkasında olup olmadığını <>
's parçası perlop
ne de while
bir parçası perlsyn
bu davranışı söz görünmektedir.
while(<>)
perlsyn, G / Ç Operatörleri ile belgelenen özel bir durumdur: 'Eğer ve eğer giriş sembolü, bir "while" ifadesinin koşulunun içindeki tek şeyse (eğer (için;;;)) döngü), değer otomatik olarak $ _ genel değişkenine atanır, daha önce
Perl'in özel değişkenlerini, nerede olursanız olun kullanın, örneğin:
$"
kullanın" "
$/
kullanın"\n"
Lexer yardımı ile garantili bir karakter uzunluğunda bir tanımlayıcı olma avantajına sahiptirler. Bu, aşağıdaki gibi anahtar kelimeye yapıştırılmasını mümkün kılar:print$.for@_
Tüm özel değişkenlerin listesi burada mevcuttur: Özel Değişkenler
Kullanmayın qw
. Bu daha iyi kullanılabilecek iki karakter kaybıdır. Örneğin, aşağıdakileri yazmayın.
@i=qw(unique value);
Bunun yerine korkaklar kullanın.
@i=(unique,value);
Veya korkak kullanamıyorsanız, glob
sözdizimini kullanın.
@i=<unique value>;
glob
Sözdizimi ilginç etkiler için de kullanılabilir.
@i=<item{1,2,3}>;
Bileşik ifadeler yerine deyim değiştiricileri kullanın.
Bileşik ifadeler, argüman için parantez ve blok için parantez gerektirme eğilimindeyken, ifade değiştiricilerin ikisine de gerek yoktur.
Karşılaştırmak:
$a++,$b++while$n--
vs while($n--){$a++;$b++}
chop$,if$c
vs if($c){chop$,}
Son örneğin $c&&chop$,
, çoğu multi-ifade işlemi için birbiriyle bağlantılı olduğunu , ancak gerçekten parlamaya başladığını unutmayın. Temel olarak işleç önceliği kaybeden bir şey &&
.
Yapma use strict
. (bu konuda bana alıntı yapmayın, PCG.SE bağlamı biraz önemlidir) Ve daha da önemlisi, katı bir kural olarak kodlamayın. Olağan Şüpheliler:
my
engelleyebilirseniz değişkenleri bildirmeyin. Gerçekten ihtiyaç duyan tek değişkenler, my
sözcüksel olarak kapsamlaştırılmasını istediğinizlerdir. Bu, golf oynarken, kapsam korumasına ihtiyaç duymadığınız ve özyinelemeyi tamamen kontrol etme eğiliminde olduğunuz herhangi biri.print hello
işe yaramayacak. Bu aslında print hello $_
( $_
filehandle yazdır hello
) anlamına gelir .
print
, ve şimdi güzel ve kısa bir örnek bulamıyorum)
Bunların bazılarının resmi isimleri olduğundan eminim ve ben sadece onların farkında değilim.
print $n++ while ($n < 10)
$var = join('',<>)
print ('X'*10) . "\n";
daha uzun olduğuprint ('X'*10) . $/;
say
işlevi şundan kısa print
, ancak kodu -E
yerine çalıştırmak zorundasınız .-e
a..z
veya hatta aralıkları kullanın aa..zz
. Bir dize olarak gerekirse, kullanın join
.$z = 'z'; print ++$z;
gösterecektiraa
Şu an tek düşünebildiğim bu. Daha sonra biraz daha ekleyebilirim.
print ('X'*10) . $/;
yapmalı? Benim için yazdırır 0
ve yeni satır yok. Birincisi, parantez içinde print
olandan daha sıkı bağlanan bir işlev tarzı çağrı argümanı olur .
. Demek istediğin bir şey x
yerine *
mi?
while
, join'',<>;
bunlar olmadan da çalışır.
Kullanma $%
yerine $a
hemen yanında bir değişken adını yerleştirmek için izin verebilir if
, for
ya da while
olduğu gibi inşa:
@r=(1,2,3,4,5);$%=4;
print$_*$%for@r
Birçoğu kullanılabilir, ancak hangilerinin sihirli etkileri olduğu konusunda docs ve @ BreadBox'ın cevaplarını kontrol edin !
İfade değiştiricileri @ JB'in yanıtına göre kullanamazsanız , harita bir bayttan tasarruf sağlayabilir:
for(@c){}
vs. map{}@c;
ve postfix for
döngülerinin içine koyabileceğiniz gibi iç içe yineleme yapmak istiyorsanız kullanışlıdır map
.
Perl 'eşleşme öncesi metin' ve 'eşleşme sonrası metin' için sihirli değişkenlere sahiptir, bu nedenle potansiyel olarak daha az karakter içeren iki gruba ayrılmak mümkündür:
($x,$y)=split/,/,$_;
($x,$y)=/(.+),(.+)/;
/,/; # $x=$`, $y=$'
# Note: you will need to save the variables if you'll be using more regex matches!
Bu ayrıca bunun yerine geçebilir substr
:
$s=substr$_,1;
/./;# $s=$'
$s=substr$_,4;
/.{4}/;# $s=$'
Maçın içeriğine ihtiyacınız olursa $&
, örneğin:
# assume input like '10 PRINT "Hello, World!"'
($n,$c,$x)=split/ /,$_;
/ .+ /; # $n=$`, $c=$&, $x=$'
print
Kodunuzda dört veya daha fazla kez söylerseniz (bu, aradığınız rutinin uzunluğuna göre açıkça değişir), daha kısa bir alt isimle değiştirin:
sub p{print@_}p;p;p;p
vs.
print;print;print;print
Gibi bir kod varsa:
$i--if$i>0
kullanabilirsiniz:
$i-=$i>0
bunun yerine bazı baytları kaydetmek için
Bir değişkeni atamıyorsanız ve breadbox'ın ipucunu kullanamıyorsanız, şu ifadeyi kullanabilirsiniz 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
Ancak, bir dizi indeksine erişmek için bir tamsayı kullanmanıza gerek kalmayacağından dikkat çekiyor:
@letters = A..Z;
$letters[rand 26]; # random letter
redo
for
veya olmayan bir bloğa döngü davranışı ekler while
. {redo}
sonsuz bir döngüdür.
İşlev çağrılarını parantez içine almayın.
Perl, NAME LIST
sözdizimini kullanarak bilinen (çekirdek veya önceden belirlenmiş) bir işlevi çağırmanıza olanak tanır . Bu &
, parantezin yanı sıra (hala kullanıyorsanız) sigilleri bırakmanıza izin verir .
Örneğin: $v=join'',<>
İç içe üçlü mantık içinde birden çok farklı ifadeyi çalıştırabilirsiniz.
Büyük bir olduğunu varsayalım if
- elsif
deyimi. Bu herhangi bir mantık ve herhangi bir sayıda ifade olabilir.
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)
Tüm komutları çalıştırmak için üçlü operatörün içinde kullanabilirsiniz .
$_ < 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
İşte sahte bir örnek:
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)
kullanınTime::HiRes
( Https://stackoverflow.com/a/896928/4739548 adresinden alınmıştır )
Birçok zorluk, tamsayılardan daha hassas biçimde uyumanızı gerektirir. select()
'ın zaman aşımı argümanı sadece bunu yapabilir.
select($u,$u,$u,0.1)
şunlardan çok daha verimli:
import Time::HiRes qw(sleep);sleep(0.1)
İlki yalnızca 20 bayttır, ikincisi ise 39'u alır. Bununla birlikte, birincisi kullanmamanızı $u
ve asla tanımlamanızı gerektirmez.
Eğer çok kullanacaksanız ithalatı karşılığını alır Time::HiRes
, ancak sadece bir kez ihtiyacınız olursa, select($u,$u,$u,0.1)
19 byte tasarruf sağlar, bu çoğu durumda kesinlikle bir gelişmedir.
Mücadelenin aksi belirtilmediği sürece, takip eden yeni satırlara ihtiyacınız yoktur.
'Mücadelemiz', '0'dan 9'a STDOUT'a rasgele bir sayı çıktı' diyor. Bu kodu alabiliriz (28 bayt):
$s=int(rand(10));print"$s\n"
Ve bunu kısaltın (25 bayt):
$s=int(rand(10));print $s
sadece değişkeni yazdırarak. Bu sonuncusu yalnızca özellikle bu zorluk için geçerlidir (19 byte):
print int(rand(10))
ancak bu yalnızca atama ve yazdırma arasındaki değişkene hiçbir şey yapmanız gerekmediğinde işe yarar.
Zaman zaman (çoğu zaman kene veya kısıtlı kaynak zorluklarıyla uğraşırken ) dize değişmezlerini yerleştirme kabiliyetinden büyük ölçüde faydalanırsınız. Normalde bunu birlikte yaparsın q(…)
. Bununla birlikte, dizgideki hangi karakterlere ihtiyacınız olduğuna bağlı olarak <…>
, glob işlecini bir bayt ve kullanım olarak kaydedebilirsiniz . (Köşeli parantezlerin içindekilerin bir dosya askısı gibi görünemeyeceğini ve bir dosya listesi listesine genişletilmesi gerektiği anlamına gelmediğini unutmayın, bu da oldukça fazla karakterin düzgün çalışamayacağı anlamına gelir.)
Bunun iyi bir örneği, girişi sinüs dalgasına dönüştüren kodu izlemektir:
s/./print" "x(sin($i+=.5)*5+5).$&/eg;
Gördüğünüz gibi, standart girdilerde karakterler üzerinde yineleme yapmanın oldukça kompakt bir yolu. İşlerin nasıl eşleştirildiğini değiştirmek için başka bir regex kullanabilirsiniz.
$_=print""
daha kısa$_=print$foo
.