TMTOWTDI
C'est le conseil de golf Perl le plus important que vous devez connaître. Chaque fois que vous regardez une séquence de caractères trop longue que vous devez absolument posséder pour pouvoir accomplir votre tâche, demandez-vous s'il n'existe pas d'autre moyen d'obtenir le même effet en utilisant une fonctionnalité différente. Il y a habituellement. Voici juste une poignée:
~~
applique un contexte scalaire et est plus court que 4 caractères scalar
.
y///c
est un caractère plus court que length
pour obtenir la longueur de $_
.
Besoin de parcourir les caractères dans $_
? Remplacer split//
par /./gs
. (Ou utilisez /./g
si vous souhaitez également ignorer les nouvelles lignes.) Cela fonctionne avec d'autres variables: remplacez split//,$x
par $x=~/./gs
.
Chaque Perl intégré renvoie quelque chose. print
renvoie 1, par exemple, pour indiquer une entrée / sortie réussie. Si vous devez initialiser $_
à une valeur vraie, par exemple, $_=print$foo
vous permet de tuer deux oiseaux avec une pierre.
Presque toutes les déclarations en Perl peuvent être écrites comme une expression, ce qui permet de les utiliser dans une plus grande variété de contextes. Plusieurs déclarations peuvent devenir plusieurs expressions chaînées avec des virgules. Les tests peuvent être effectués avec des opérateurs de court-circuit ?:
&&
||
, mais également avec and
et or
, qui font la même chose, mais avec une priorité inférieure à celle de tous les autres opérateurs (y compris l'affectation). Les boucles peuvent être effectuées via map
ou grep
. Même des mots clés tels que next
, last
et return
peuvent être utilisés dans un contexte d'expression, même s'ils ne sont pas renvoyés! En gardant à l'esprit ce type de transformations, vous pouvez remplacer les blocs de code par des expressions pouvant être intégrées à une plus grande variété de contextes.
$_=print""
est plus court que$_=print$foo
.$foo
. Sinon,$_=1
est beaucoup plus courte que$_=print""
et a le même effet.$x
? Sinon, vous pourriez simplement faire/./gs
et/./g
.Abuser des variables spéciales de Perl!
Comme indiqué dans une réponse précédente
$/
, ils$"
sont initialisés par défaut à"\n"
et" "
, respectivement.$,
et$\
sont tous deux réglésundef
par défaut et ont 3 caractères plus courts.Si
$\
vous définissez une valeur, elle sera ajoutée à chaqueprint
. Par exemple:perl -ple '$\="=".hex.$/'
est un convertisseur hexadécimal très pratique.Si vous ne lisez pas de fichiers à partir de la ligne de commande, vous pouvez utiliser le
-i
commutateur de ligne de commande comme canal supplémentaire pour la saisie d'une chaîne. Sa valeur sera stockée dans$^I
.$=
oblige tout ce qui lui est assigné à être un entier. Essayez de courirperl -ple '$_=$==$_'
et de lui donner divers problèmes. De même,$-
force sa valeur à être un entier non négatif (c’est-à-dire qu’un tiret est traité comme un caractère non numérique).Vous pouvez utiliser
$.
un indicateur booléen qui est automatiquement réinitialisé sur une valeur vraie (différente de zéro) à chaque itération d'unewhile(<>)
boucle.la source
-n
et accolades inégaléesIl est bien connu que le commutateur de ligne de commande
-n
peut être utilisé pour exécuter le script une fois pour chaque ligne.perl --help
dit:Ce que cela ne dit pas explicitement, c'est que Perl n'assume pas simplement une boucle autour du programme; il s'enroule littéralement
while (<>) { ... }
autour de lui.De cette façon, les commandes suivantes sont équivalentes:
-p
et accolades inégaléesDe même que ci-dessus, le
-p
commutateurwhile (<>) { ... ; print }
entoure le programme.En utilisant des accolades sans correspondance,
perl -p 'code}{morecode'
n’imprimera qu’une fois après avoir été exécutécode
pour toutes les lignes d’entrée, suivi demorecode
.Comme
$_
indéfini quandmorecode;print
est exécuté, le séparateur d'enregistrement de sortie$\
peut être utilisé pour imprimer la sortie réelle.Par exemple
lit un numéro par ligne à partir de STDIN et imprime sa somme.
la source
#!perl -n
la première ligne, non?-p
et$\
) pour la première fois dans une des réponses Perl de @primo . Lire ses réponses est un bon conseil Perl en soi.}for(...){
entre les accolades est souvent très pratique aussi, par exemple codegolf.stackexchange.com/a/25632Utilisez
$_
pour éliminer les références scalaires. Il s’agit de la variable spéciale utilisée par défaut par la plupart des fonctions et le fait de laisser des paramètres de côté est un raccourci pour référencer cette variable.En changeant
$n
à$_
, vous pouvez changer$n=<>;chop$n;print$n
en$_=<>;chop;print
Ici, la
print
fonction imprime le contenu de$_
par défaut etchop
fonctionne également$_
.la source
$_=<>;
requis, ne<>;
lit pas la ligne$_
automatiquement?$_=<>;print
et<>;print
. Le premier me répète ce que je tape, alors que l'autre ne le fait pas.print while(<>)
. Je ne sais pas si c'est un cas particulier ou il y a une certaine logique cohérente derrière elle, ni<>
fait partie de dans ,perlop
ni unewhile
partie deperlsyn
semblent parler de ce comportement.while(<>)
est un cas particulier, documenté dans perlsyn, Opérateurs d'E / S: 'Si et seulement si le symbole d'entrée est la seule chose dans le conditionnel d'une instruction "while" (même si déguisé en "for (;;)" boucle), la valeur est automatiquement affectée à la variable globale $ _, détruisant tout ce qui s'y trouvait auparavant. "Utilisez les variables spéciales de Perl chaque fois que vous le pouvez, par exemple:
$"
au lieu de" "
$/
au lieu de"\n"
Ils ont l’avantage supplémentaire d’être un identifiant long garanti d’un caractère, avec l’aide du lexer. Cela permet de le coller au mot clé qui le suit, comme dans:
print$.for@_
La liste de toutes les variables spéciales est disponible ici: Variables spéciales
la source
Ne pas utiliser
qw
. C'est un gaspillage de deux personnages qui pourraient être utilisés de manière plus efficace. Par exemple, n'écrivez pas ce qui suit.Utilisez plutôt des mots nus.
Ou si vous ne pouvez pas utiliser de mots nus, utilisez la
glob
syntaxe.glob
la syntaxe peut également être utilisée pour des effets intéressants.la source
Utilisez des modificateurs d'instruction au lieu d'instructions composées.
Les instructions composées ont tendance à exiger des parenthèses pour l'argument et des accolades pour le bloc, alors que les modificateurs d'instruction ne nécessitent ni l'un ni l'autre.
Comparer:
$a++,$b++while$n--
contrewhile($n--){$a++;$b++}
chop$,if$c
contreif($c){chop$,}
Notez que le dernier exemple est lié à
$c&&chop$,
, mais commence vraiment à briller pour la plupart des opérations multi-instructions. Fondamentalement, tout ce qui fait perdre la priorité à l'opérateur&&
.la source
Ne pas
use strict
. (Ne me citez pas à ce sujet, le contexte de PCG.SE est un peu important) et, plus important encore, ne codez pas comme si vous étiez sous stricte. Les suspects habituels:my
-déclare pas les variables si tu peux l'éviter. Les seules variables dontmy
vous avez réellement besoin sont celles que vous souhaitez définir de manière lexicale. C’est à peine si vous jouez au golf, pour lequel vous n’avez pas besoin de protection et qui ont tendance à contrôler totalement la récursivité.la source
print hello
ne fonctionnera pas. Cela signifie réellementprint hello $_
(print$_
to filehandlehello
).print
, et maintenant je ne trouve pas un exemple court et agréable)Je suis sûr que certains d'entre eux ont des noms officiels et je ne les connais tout simplement pas.
print $n++ while ($n < 10)
$var = join('',<>)
print ('X'*10) . "\n";
est plus long queprint ('X'*10) . $/;
say
fonction de Perl est plus courte queprint
, mais vous devrez exécuter le code avec-E
au lieu de-e
a..z
ou mêmeaa..zz
. Si nécessaire en tant que chaîne, utilisezjoin
.$z = 'z'; print ++$z;
afficheraaa
C'est tout ce à quoi je peux penser maintenant. J'en ajouterai peut-être plus tard.
la source
print ('X'*10) . $/;
censé faire? Pour moi, il imprime0
et pas de nouvelle ligne. D'une part, les parenthèses deviennent un argument d'appel de style de fonctionprint
, qui lie plus étroitement que.
. Et avez-vous voulu direx
au lieu de*
ou quelque chose?while
, celajoin'',<>;
fonctionne aussi sans elles.Utilisez des caractères autres que des mots comme noms de variables
Utiliser
$%
au lieu de$a
peut vous permettre de placer le nom de variable juste à côté d'unif
,for
ou dewhile
construire comme dans:@r=(1,2,3,4,5);$%=4;
print$_*$%for@r
Beaucoup peuvent être utilisés, mais vérifiez la documentation et la réponse de @ BreadBox pour savoir lesquelles ont des effets magiques!
Utiliser la carte lorsque vous ne pouvez pas utiliser les modificateurs d'instruction
Si vous ne pouvez pas utiliser l'instruction modfier selon la réponse de @ JB , map peut enregistrer un octet:
for(@c){}
contre.map{}@c;
et est utile si vous voulez faire des itérations imbriquées car vous pouvez mettre des
for
boucles postfix dans lemap
.Utilisez toutes les variables magiques des expressions régulières
Perl a des variables magiques pour 'texte avant correspondance' et 'texte après correspondance', il est donc possible de scinder en groupes de deux avec potentiellement moins de caractères:
Cela pourrait également bien fonctionner en remplacement de
substr
:Si vous avez besoin du contenu de la correspondance, vous
$&
pouvez l'utiliser, par exemple:Remplacer les sous-noms par des noms longs par des noms plus courts
Si vous appelez
print
plusieurs fois dans votre code (cela dépend évidemment de la durée de la routine que vous appelez), remplacez-le par un nom de sous-nom plus court:contre.
Remplacer les incrémenteurs / décrémenteurs conditionnels
Si vous avez un code comme:
vous pouvez utiliser:
au lieu de sauver quelques octets.
Convertir en entier
Si vous n'affectez pas de variable et ne pouvez donc pas utiliser le conseil de breadbox , vous pouvez utiliser l'expression
0|
:Il est à noter cependant que vous n'avez pas besoin d'utiliser un entier pour accéder à un index de tableau:
la source
redo
ajoute le comportement de la boucle à un bloc sansfor
ouwhile
.{redo}
est une boucle infinie.la source
Ne mettez pas entre parenthèses les appels de fonction.
Perl vous permet d'appeler une fonction connue (principale ou prédéclarée) à l'aide de la
NAME LIST
syntaxe. Cela vous permet de supprimer le&
sigil (si vous l'utilisiez encore) ainsi que les parenthèses.Par exemple:
$v=join'',<>
Documentation complète
la source
Essayez d'utiliser la valeur d'une expression d'affectation, comme suit:
Cela fonctionne car il
$n
y a 2 caractères en Perl. Vous pouvez changer$n
à()
sans frais et enregistrer 1 virgule en déplaçant l'affectation dans les parenthèses.la source
Vous pouvez exécuter plusieurs instructions différentes dans la logique ternaire imbriquée.
Supposons que vous ayez une grande
if
-elsif
déclaration. Cela pourrait être n'importe quelle logique et n'importe quel nombre d'énoncés.Vous pouvez utiliser
(cmd1, cmd2, cmd3)
l'opérateur ternaire pour exécuter toutes les commandes.Voici un exemple factice:
la source
Utiliser
select(undef,undef,undef,$timeout)
au lieu deTime::HiRes
(Tiré de https://stackoverflow.com/a/896928/4739548 )
De nombreux défis vous obligent à dormir avec une précision supérieure à celle des nombres entiers.
select()
L'argument de délai d'attente peut faire exactement cela.est beaucoup plus efficace que:
Le premier ne fait que 20 octets, alors que le dernier en occupe 39. Cependant, le premier exige que vous n'utilisiez pas
$u
et que vous ne l'ayez jamais défini.Si vous comptez vous en servir, l'importation vous
Time::HiRes
rapporte beaucoup , mais si vous n'en avez besoin qu'une seule fois, vousselect($u,$u,$u,0.1)
économisez 19 octets, ce qui est certainement une amélioration dans la plupart des cas.la source
Raccourcissez vos relevés d'impression
Sauf indication contraire du défi, vous n'avez pas besoin de nouvelles lignes.
Notre "défi" dit "affiche un nombre aléatoire de 0 à 9 pour STDOUT". Nous pouvons prendre ce code (28 octets):
Et raccourcissez-le à ceci (25 octets):
en imprimant simplement la variable. Ce dernier s'applique uniquement à ce défi (19 octets):
mais cela ne fonctionne que lorsque vous n'avez rien à faire avec la variable entre affectation et impression.
la source
Utilisez des globes comme des littéraux de chaîne
De temps en temps (souvent lorsqu’il s’agit de problèmes de quine ou de sources restreintes ), vous bénéficiez grandement de la possibilité d’imbriquer des littéraux de chaîne. Normalement, vous le feriez avec
q(…)
. Toutefois, en fonction des caractères dont vous avez besoin dans la chaîne, vous pourrez peut-être enregistrer un octet et utiliser<…>
l'opérateur glob. (Notez que ce qui se trouve à l'intérieur des crochets n'apparaît pas comme un descripteur de fichier, ni comme il est censé être étendu à une liste de noms de fichiers, ce qui signifie qu'un grand nombre de caractères ne fonctionneront pas correctement.)la source
Utilisez l'expression regexe.
Une illustration décente de ceci est le code suivant façonnant l’entrée en onde sinusoïdale:
Comme vous pouvez le constater, c’est un moyen relativement compact d’itérer sur des caractères en entrée standard. Vous pouvez utiliser d'autres expressions rationnelles pour changer la façon dont les choses correspondent.
la source