TMTOWTDI
Das ist der wichtigste Perl-Golftipp, den Sie kennen müssen. Wenn Sie eine zu lange Folge von Zeichen betrachten, die Sie unbedingt benötigen, um Ihre Aufgabe zu erfüllen, fragen Sie sich, ob es keine andere Möglichkeit gibt, den gleichen Effekt mit einer anderen Funktion zu erzielen. Das gibt es normalerweise. Hier sind nur eine Handvoll:
~~
Erzwingt einen skalaren Kontext und ist 4 Zeichen kürzer als scalar
.
y///c
ist ein char kürzer als length
wenn man die länge von $_
.
Müssen Sie die Zeichen in iterieren $_
? Ersetzen split//
durch /./gs
. (Oder verwenden /./g
Sie, wenn Sie auch Zeilenumbrüche überspringen möchten.) Dies funktioniert mit anderen Variablen: Ersetzen split//,$x
durch $x=~/./gs
.
Jedes eingebaute Perl gibt etwas zurück. print
gibt beispielsweise 1 zurück, um eine erfolgreiche E / A anzuzeigen. Wenn Sie $_
zum Beispiel auf einen wahren Wert initialisieren müssen , $_=print$foo
können Sie zwei Fliegen mit einer Klappe schlagen.
Fast jede Anweisung in Perl kann als Ausdruck geschrieben werden, sodass sie in einer Vielzahl von Kontexten verwendet werden kann. Mehrere Anweisungen können zu mehreren Ausdrücken werden, die mit Kommas verkettet sind. Tests können mit Kurzschlussoperatoren ?:
&&
||
sowie mit and
und durchgeführt werden or
, die dasselbe tun, jedoch mit einer niedrigeren Priorität als alle anderen Operatoren (einschließlich Zuweisung). Loops können über map
oder durchgeführt werden grep
. Auch Schlüsselwörter wie next
, last
und return
kann in einem Ausdruck Kontext verwendet werden, auch wenn sie nicht zurück! Wenn Sie diese Art von Transformationen berücksichtigen, haben Sie die Möglichkeit, Codeblöcke durch Ausdrücke zu ersetzen, die in eine Vielzahl von Kontexten eingefügt werden können.
$_=print""
ist kürzer als$_=print$foo
.$foo
. Ansonsten$_=1
ist viel kürzer als$_=print""
und hat den gleichen Effekt.$x
? Ansonsten könnte man einfach/./gs
und/./g
.Missbrauche Perls spezielle Variablen!
Wie in einer vorherigen Antwort erwähnt
$/
und$"
standardmäßig mit"\n"
und initialisiert" "
.$,
und$\
sind beideundef
voreingestellt und 3 Zeichen kürzer.Wenn Sie
$\
einen Wert festlegen , wird dieser an jeden Wert angehängtprint
. Zum Beispiel:perl -ple '$\="=".hex.$/'
ist ein praktischer Hex-zu-Dezimal-Konverter.Wenn Sie keine Dateien über die Befehlszeile lesen, können Sie die
-i
Befehlszeilenoption als zusätzlichen Kanal für die Eingabe einer Zeichenfolge verwenden. Sein Wert wird in gespeichert$^I
.$=
Erzwingt, dass alles, was ihm zugewiesen ist, eine Ganzzahl ist. Laufen Sieperl -ple '$_=$==$_'
und geben Sie ihm verschiedene Einbrüche. Erzwingt ebenfalls, dass$-
sein Wert eine nicht negative Ganzzahl ist (dh ein führender Strich wird als nicht numerisches Zeichen behandelt).Sie können es
$.
als Boolesches Flag verwenden, das bei jeder Iteration einerwhile(<>)
Schleife automatisch auf einen wahren Wert (ungleich Null) zurückgesetzt wird.quelle
-n
und unvergleichliche geschweifte KlammernEs ist bekannt, dass der Befehlszeilenschalter
-n
verwendet werden kann, um das Skript einmal für jede Zeile auszuführen.perl --help
sagt:Was nicht explizit gesagt wird, ist, dass Perl nicht nur eine Schleife um das Programm herum annimmt. es wickelt sich buchstäblich darum
while (<>) { ... }
.Auf diese Weise sind die folgenden Befehle einander äquivalent:
-p
und unvergleichliche geschweifte KlammernÄhnlich wie oben wird das Programm mit dem
-p
Schalter umbrochenwhile (<>) { ... ; print }
.Wenn Sie nicht übereinstimmende geschweifte Klammern verwenden,
perl -p 'code}{morecode'
wird nach der Ausführungcode
für alle Eingabezeilen nur einmal gedruckt , gefolgt vonmorecode
.Da
$_
undefiniertmorecode;print
ist, wann ausgeführt wird, kann das Trennzeichen$\
für Ausgabedatensätze zum Drucken der tatsächlichen Ausgabe missbraucht werden.Zum Beispiel
Liest eine Zahl pro Zeile aus STDIN und gibt deren Summe aus.
quelle
#!perl -n
in der ersten Zeile erreichen können, oder?-p
und$\
) zum ersten Mal in einer von @primos Perl-Antworten gesehen. Seine Antworten zu lesen ist ein guter Perl-Tipp für sich.}for(...){
zwischen die Klammern zu werfen ist oft auch ganz praktisch, zB codegolf.stackexchange.com/a/25632Verwenden Sie
$_
diese Option , um skalare Referenzen zu entfernen. Es ist die spezielle Variable, die von den meisten Funktionen als Standard verwendet wird. Das Weglassen von Parametern ist eine Abkürzung, um auf diese Variable zu verweisen.Durch die Änderung
$n
zu$_
, können Sie ändern$n=<>;chop$n;print$n
zu$_=<>;chop;print
Hier
print
druckt die Funktion$_
standardmäßig den Inhalt von undchop
arbeitet auch daran$_
.quelle
$_=<>;
erforderlich,<>;
liest die Zeile nicht$_
automatisch ein?$_=<>;print
und verglichen<>;print
. Der erste wiederholt mir, was ich tippe, der andere nicht.print while(<>)
. Ich bin mir nicht sicher, ob es sich um einen Sonderfall handelt oder ob eine zusammenhängende Logik dahinter steckt. Weder<>
inperlop
noch inwhile
Teilenperlsyn
scheint dieses Verhalten zu erwähnen.while(<>)
ist ein Sonderfall, der in Perlsyn, I / O-Operatoren, dokumentiert ist: "Wenn und nur wenn das Eingabesymbol das einzige ist, was in der Bedingung einer" while " -Anweisung enthalten ist (auch wenn es als" for (;;) "getarnt ist. Schleife) wird der Wert automatisch der globalen Variablen $ _ zugewiesen, wodurch alles zerstört wird, was vorher da war. "Verwenden Sie die speziellen Variablen von Perl, wo immer Sie können, zB:
$"
anstelle von" "
$/
anstelle von"\n"
Sie haben den zusätzlichen Vorteil, dass sie mit Hilfe des Lexers eine garantierte Kennung mit einer Länge von einem Zeichen sind. Dies ermöglicht es, es mit dem darauf folgenden Schlüsselwort zu verkleben, wie in:
print$.for@_
Die Liste aller speziellen Variablen finden Sie hier: Spezielle Variablen
quelle
Nicht verwenden
qw
. Dies ist Verschwendung von zwei Zeichen, die besser verwendet werden könnten. Schreiben Sie beispielsweise Folgendes nicht.Verwenden Sie stattdessen Barewords.
Wenn Sie keine Barewords verwenden können, verwenden Sie die
glob
Syntax.glob
Die Syntax kann auch für interessante Effekte verwendet werden.quelle
Verwenden Sie Anweisungsmodifizierer anstelle von zusammengesetzten Anweisungen.
Für zusammengesetzte Anweisungen sind in der Regel Klammern für das Argument und geschweifte Klammern für den Block erforderlich, während Anweisungsmodifikatoren keine benötigen.
Vergleichen Sie:
$a++,$b++while$n--
vswhile($n--){$a++;$b++}
chop$,if$c
vsif($c){chop$,}
Beachten Sie, dass das letzte Beispiel zwar an die
$c&&chop$,
meisten Operationen mit mehreren Anweisungen anknüpft , aber für diese auch wirklich zu glänzen beginnt. Grundsätzlich alles, was den Vorrang des Bedieners verliert&&
.quelle
Nicht
use strict
. (Zitieren Sie mich nicht dazu, der PCG.SE-Kontext spielt eine Rolle.) Und, was noch wichtiger ist, codieren Sie nicht wie unter strikt. Die üblichen Verdächtigen:my
Deklarieren Sie keine Variablen, wenn Sie dies vermeiden können. Die einzigen Variablen, die wirklich benötigt werden,my
sind diejenigen, die lexikalisch abgegrenzt werden sollen. Dies ist beim Golfen kaum einer der Fälle, in denen Sie keinen Oszilloskopschutz benötigen und die Rekursion in der Regel vollständig kontrollieren.quelle
print hello
wird nicht funktionieren. Es bedeutet eigentlichprint hello $_
(Drucken$_
in Dateihandlehello
).print
, und jetzt kann ich kein schönes und kurzes Beispiel finden)Ich bin mir sicher, dass einige von ihnen formelle Namen haben und ich bin mir ihrer einfach nicht bewusst.
print $n++ while ($n < 10)
$var = join('',<>)
print ('X'*10) . "\n";
länger alsprint ('X'*10) . $/;
say
Funktion ist kürzer alsprint
, aber Sie müssen den Code mit-E
anstelle von ausführen-e
a..z
oder sogaraa..zz
. Bei Bedarf als Zeichenfolge verwendenjoin
.$z = 'z'; print ++$z;
wird angezeigtaa
Das ist alles, woran ich gerade denken kann. Ich kann später noch etwas hinzufügen.
quelle
print ('X'*10) . $/;
soll ich tun? Bei mir druckt es0
und kein Zeilenumbruch. Zum einen werden die Klammern zu einem Aufrufargument im Funktionsstilprint
, das enger als bindet.
. Und meintest dux
stattdessen*
oder so?while
undjoin'',<>;
funktioniert auch ohne diese.Verwenden Sie Nicht-Wort-Zeichen als Variablennamen
Mit
$%
statt$a
ermöglicht es Ihnen , die Variablennamen zu setzen direkt neben einif
,for
oderwhile
zu konstruieren , wie in:@r=(1,2,3,4,5);$%=4;
print$_*$%for@r
Viele können verwendet werden, aber schauen Sie in den Dokumenten und in der Antwort von @ BreadBox nach, welche davon magische Effekte haben!
Verwenden Sie map, wenn Sie keine Anweisungsmodifikatoren verwenden können
Wenn Sie keine Anweisungsmodifikatoren gemäß der Antwort von @ JB verwenden können , speichert map möglicherweise ein Byte:
for(@c){}
gegenmap{}@c;
und ist nützlich, wenn Sie verschachtelte Iterationen ausführen möchten, da Sie Postfix-
for
Schleifen in das einfügen könnenmap
.Verwenden Sie alle magischen Variablen für reguläre Ausdrücke
Perl verfügt über magische Variablen für 'Text vor dem Abgleich' und 'Text nach dem Abgleich', sodass es möglich ist, in Zweiergruppen mit möglicherweise weniger Zeichen aufzuteilen:
Dies kann auch als Ersatz für Folgendes verwendet werden
substr
:Wenn Sie den Inhalt des Spiels benötigen,
$&
können verwendet werden, zB:Ersetzen Sie Subs mit langen Namen durch einen kürzeren Namen
Wenn Sie
print
in Ihrem Code vier oder mehr Male sagen (dies hängt natürlich von der Länge der aufgerufenen Routine ab), ersetzen Sie ihn durch einen kürzeren Subnamen:gegen
Ersetzen Sie bedingte Inkrementierer / Dekrementierer
Wenn Sie Code haben wie:
Sie können verwenden:
stattdessen, um einige Bytes zu speichern.
In Ganzzahl konvertieren
Wenn Sie keiner Variablen zuweisen und daher den Tipp der Brotbox nicht verwenden können, können Sie den folgenden Ausdruck verwenden
0|
:Beachten Sie jedoch, dass Sie keine Ganzzahl benötigen, um auf einen Array-Index zuzugreifen:
quelle
redo
Fügt einem Block ohnefor
oder ein Schleifenverhalten hinzuwhile
.{redo}
ist eine Endlosschleife.quelle
Setzen Sie keine Funktionsaufrufe in Klammern.
Mit Perl können Sie eine bekannte (Core oder Predeclared) Funktion mithilfe der
NAME LIST
Syntax aufrufen . Auf diese Weise können Sie das&
Siegel (falls Sie es noch verwendet haben) sowie die Klammern fallen lassen.Zum Beispiel:
$v=join'',<>
Vollständige Dokumentation
quelle
Versuchen Sie, den Wert eines Zuweisungsausdrucks wie folgt zu verwenden:
Das funktioniert, weil
$n
es in Perl 2 Zeichen gibt. Sie können kostenlos$n
zu wechseln()
und 1 Semikolon speichern, indem Sie die Zuordnung in die Klammern setzen.quelle
Sie können innerhalb der verschachtelten ternären Logik mehrere verschiedene Anweisungen ausführen.
Angenommen , Sie haben eine große
if
-elsif
Anweisung. Dies kann eine beliebige Logik und eine beliebige Anzahl von Anweisungen sein.Sie können
(cmd1, cmd2, cmd3)
innerhalb des ternären Operators alle Befehle ausführen.Hier ist ein Dummy-Beispiel:
quelle
Verwenden Sie
select(undef,undef,undef,$timeout)
anstelle vonTime::HiRes
(Entnommen aus https://stackoverflow.com/a/896928/4739548 )
Bei vielen Herausforderungen müssen Sie präziser schlafen als ganze Zahlen.
select()
Das Timeout-Argument von kann genau das.ist viel effizienter als:
Ersteres hat nur 20 Byte, während Letzteres 39 Byte belegt. Ersteres erfordert jedoch, dass Sie es nicht verwenden
$u
und es nie definiert haben.Wenn Sie es viel verwenden werden,
Time::HiRes
lohnt sich der Import , aber wenn Sie es nur einmal benötigen,select($u,$u,$u,0.1)
spart die Verwendung von 19 Byte, was in den meisten Fällen definitiv eine Verbesserung darstellt.quelle
Kürzen Sie Ihre Druckanweisungen
Sofern die Aufforderung nichts anderes angibt, brauchen Sie keine nachgestellten Zeilenumbrüche.
Unsere "Herausforderung" lautet "Ausgabe einer Zufallszahl von 0 bis 9 an STDOUT". Wir können diesen Code (28 Bytes) nehmen:
Und verkürzen Sie es auf dieses (25 Bytes):
indem Sie einfach die Variable drucken. Letzteres gilt nur für diese spezielle Herausforderung (19 Byte):
Dies funktioniert jedoch nur, wenn Sie zwischen Zuweisung und Drucken nichts an der Variablen vornehmen müssen.
quelle
Verwenden Sie Globs wie String-Literale
Gelegentlich (häufig bei quinen oder quellenbeschränkten Herausforderungen) profitieren Sie stark von der Fähigkeit, String-Literale zu verschachteln. Normalerweise würden Sie dies mit tun
q(…)
. Abhängig davon, welche Zeichen Sie in der Zeichenfolge benötigen, können Sie möglicherweise ein Byte speichern und<…>
den Glob-Operator verwenden. (Beachten Sie, dass das, was sich in den spitzen Klammern befindet, nicht wie ein Dateihandle aussehen kann und auch nicht so aussehen kann, als ob es zu einer Liste von Dateinamen erweitert werden soll, was bedeutet, dass eine ganze Reihe von Zeichen nicht richtig funktionieren.)quelle
Verwenden Sie den Ausdruck Regex.
Ein gutes Beispiel dafür ist folgender Code, der die Eingabe in eine Sinuswelle umwandelt:
Wie Sie sehen, ist es eine recht kompakte Methode, Zeichen in der Standardeingabe zu durchlaufen. Sie können andere reguläre Ausdrücke verwenden, um die Art und Weise zu ändern, in der die Dinge aufeinander abgestimmt sind.
quelle