Fonctionnalités cachées de Perl?


143

Quelles sont les fonctionnalités de langage vraiment utiles mais ésotériques de Perl que vous avez pu utiliser pour faire un travail utile?

Des lignes directrices:

  • Essayez de limiter les réponses au cœur Perl et non au CPAN
  • Veuillez donner un exemple et une brève description

Fonctionnalités cachées également trouvées dans les fonctionnalités cachées d'autres langues:

(Tout cela vient de la réponse de Corion )

  • C
    • L'appareil de Duff
    • Portabilité et standardité
  • C #
    • Citations pour les listes et les chaînes délimitées par des espaces
    • Espaces de noms aliasables
  • Java
    • Initaliseurs statiques
  • JavaScript
    • Les fonctions sont des citoyens de première classe
    • Bloquer la portée et la fermeture
    • Appeler indirectement des méthodes et des accesseurs via une variable
  • Rubis
    • Définition de méthodes via le code
  • PHP
    • Documentation en ligne omniprésente
    • Méthodes magiques
    • Références symboliques
  • Python
    • Échange de valeur sur une ligne
    • Possibilité de remplacer même les fonctions de base par vos propres fonctionnalités

Autres fonctionnalités cachées:

Les opérateurs:

Citant des constructions:

Syntaxe et noms:

Modules, pragmas et options de ligne de commande:

Variables:

Boucles et contrôle de flux:

Expressions régulières:

Autres caractéristiques:

Autres astuces et méta-réponses:


Voir également:


La plupart de ces fonctionnalités sont utilisées tous les jours, certaines se produisent dans la majorité des scripts Perl, et la plupart répertoriées sous "Autre" proviennent encore d'autres langages, appelant ces changements "cachés" l'intention de la question.
reinierpost

Réponses:


54

L'opérateur flip-flop est utile pour ignorer la première itération lors de la lecture en boucle des enregistrements (généralement des lignes) renvoyés par un descripteur de fichier, sans utiliser de variable indicateur:

while(<$fh>)
{
  next if 1..1; # skip first record
  ...
}

Exécutez perldoc perlopet recherchez "flip-flop" pour plus d'informations et d'exemples.


En fait, c'est tiré d'Awk, où vous pouvez faire une bascule entre deux modèles en écrivant pattern1, pattern2
Bruno De Fraine

15
Pour clarifier, l'aspect "caché" de ceci est que si l'un des opérandes au scalaire '..' est une constante, la valeur est implicitement comparée au numéro de ligne d'entrée ($.)
Michael Carman

47

Il existe de nombreuses fonctionnalités non évidentes dans Perl.

Par exemple, saviez-vous qu'il peut y avoir un espace après un sceau?

 $ perl -wle 'my $x = 3; print $ x'
 3

Ou que vous pouvez donner des noms numériques aux sous-titres si vous utilisez des références symboliques?

$ perl -lwe '*4 = sub { print "yes" }; 4->()' 
yes

Il y a aussi le quasi-opérateur "bool", qui renvoie 1 pour les expressions vraies et la chaîne vide pour les faux:

$ perl -wle 'print !!4'
1
$ perl -wle 'print !!"0 but true"'
1
$ perl -wle 'print !!0'
(empty line)

Autre truc intéressant: avec use overloadvous pouvez surcharger les chaînes littérales et les nombres (et par exemple les rendre BigInts ou autre).

Beaucoup de ces choses sont en fait documentées quelque part, ou découlent logiquement des fonctionnalités documentées, mais certaines ne sont néanmoins pas très connues.

Mise à jour : une autre belle. Ci-dessous, les q{...}constructions de citation ont été mentionnées, mais saviez-vous que vous pouvez utiliser des lettres comme délimiteurs?

$ perl -Mstrict  -wle 'print q bJet another perl hacker.b'
Jet another perl hacker.

De même, vous pouvez écrire des expressions régulières:

m xabcx
# same as m/abc/

2
«Saviez-vous qu'il peut y avoir un espace après un sceau?» Je suis complètement sidéré. Sensationnel.
Aristote Pagaltzis

1
Cool! !! $ undef_var ne crée pas d'avertissement.
Axeman

4
Je pense que votre exemple d'utilisation de lettres pour délimiter des chaînes devrait être " Just another perl hacker" plutôt que "Jet another perl hacker" = P
Chris Lutz

Le pire, c'est que vous pouvez également utiliser d'autres éléments comme délimiteurs. Même fermant les crochets. Les éléments suivants sont valides: s} regex} replacement} xsmg; q] chaîne littérale];
Ryan C. Thompson

46

Ajout de la prise en charge des fichiers compressés via ARGV magique :

s{ 
    ^            # make sure to get whole filename
    ( 
      [^'] +     # at least one non-quote
      \.         # extension dot
      (?:        # now either suffix
          gz
        | Z 
       )
    )
    \z           # through the end
}{gzcat '$1' |}xs for @ARGV;

(guillemets autour de $ _ nécessaires pour gérer les noms de fichiers avec des métacaractères shell)

Désormais, la <>fonction décompresse tous les @ARGVfichiers qui se terminent par ".gz" ou ".Z":

while (<>) {
    print;
}

2
Je ne pense pas que vous ayez besoin d'échapper |au remplacement.
Chris Lutz

Je regarde ça et je n'arrive pas à comprendre comment ça marche. À quel moment est-il zcat |analysé comme une commande à traverser?
Ether

1
@Ether => la détection des tuyaux est une fonctionnalité des deux arguments open, que l'opérateur diamant utilise pour ouvrir chaque fichier dans@ARGV
Eric Strom

40

L'une de mes fonctionnalités préférées en Perl est d'utiliser l' ||opérateur booléen pour choisir entre un ensemble de choix.

 $x = $a || $b;

 # $x = $a, if $a is true.
 # $x = $b, otherwise

Cela signifie que l'on peut écrire:

 $x = $a || $b || $c || 0;

de prendre la première vraie valeur de $a, $bet $c, ou un défaut 0autrement.

En Perl 5.10, il y a aussi l' //opérateur, qui renvoie le côté gauche s'il est défini, et le côté droit sinon. Les sélections suivantes de la première définie valeur de $a, $b, $c, ou 0autrement:

$ x = $ a // $ b // $ c // 0;

Ceux-ci peuvent également être utilisés avec leurs formes abrégées, qui sont très utiles pour fournir des valeurs par défaut:

$ x || = 0; # Si $ x était faux, il a maintenant une valeur de 0.

$ x // = 0; # Si $ x n'était pas défini, il a maintenant une valeur de zéro.

Cheerio,

Paul


4
C'est un idiome tellement courant qu'il n'est guère qualifié de fonction «cachée».
Michael Carman

3
dommage que la jolie imprimante pense // est un commentaire :)
John Ferguson

2
Question, y a-t-il une "fonction d'utilisation" pour utiliser ces nouveaux opérateurs, ou sont-ils activés par défaut? Je me penche toujours sur les fonctionnalités de Perl 5.10.
JJ

6
// est là par défaut, aucun ajustement spécial n'est nécessaire. Vous pouvez également le rétroporter dans 5.8.x avec le dor-patch ... voir le répertoire auteurs / id / H / HM / HMBRAND / sur n'importe quel miroir CPAN. FreeBSD 6.x et les versions ultérieures le font pour vous dans leur paquet perl.
dland

2
Quand || ou // est combiné avec do {}, vous pouvez encapsuler une affectation plus complexe, ie $ x = $ a || faire {mon $ z; 3 ou 4 lignes de dérivation; $ z};
RET

39

Les opérateurs ++ et unaire - ne fonctionnent pas seulement sur les nombres, mais aussi sur les chaînes.

my $_ = "a"
print -$_

impressions -a

print ++$_

impressions b

$_ = 'z'
print ++$_

imprime aa


3
Pour citer perlvar: "L'opérateur de décrémentation automatique n'est pas magique." Donc --ne fonctionne pas sur les chaînes.
moritz

"aa" ne semble pas être l'élément naturel suivant "z". Je m'attendrais à la prochaine valeur ascii la plus élevée, qui est "{".
Ether

4
Ne demandez pas à un programmeur ce qui vient après "z"; demande à un humain. Cette fonctionnalité est idéale pour numéroter des éléments dans une longue liste.
Barry Brown

17
Quand j'étais nouveau dans Perl, j'ai implémenté cette fonctionnalité moi-même avec le comportement exact de z à aa, puis je l'ai montrée à un collègue qui a ri et m'a dit "laissez-moi vous montrer quelque chose". J'ai pleuré un peu mais j'ai appris quelque chose.
Copas

2
@Ether - Si vous le souhaitez, utilisez des nombres et convertissez-les automatiquement en ASCII avec ord(). Ou écrivez une petite classe et surchargez les opérateurs pour le faire à votre place.
Chris Lutz

36

Comme Perl a presque toutes les parties "ésotériques" des autres listes, je vais vous dire une chose que Perl ne peut pas:

La seule chose que Perl ne peut pas faire est d'avoir des URL arbitraires nues dans votre code, car l' //opérateur est utilisé pour les expressions régulières.

Juste au cas où vous ne sauriez pas quelles sont les fonctionnalités offertes par Perl, voici une liste sélective des entrées peut-être pas totalement évidentes:

Appareil de Duff - en Perl

Portabilité et standardité - Il y a probablement plus d'ordinateurs avec Perl qu'avec un compilateur C

Une classe de manipulation de fichiers / chemins - File :: Find fonctionne sur encore plus de systèmes d'exploitation que .Net

Citations pour les listes et les chaînes délimitées par des espaces - Perl vous permet de choisir des guillemets presque arbitraires pour votre liste et les délimiteurs de chaîne

Espaces de noms aliasables - Perl les a via des affectations globales:

*My::Namespace:: = \%Your::Namespace

Initialiseurs statiques - Perl peut exécuter du code dans presque toutes les phases de compilation et d'instanciation d'objet, de BEGIN(analyse de code) à CHECK(après analyse de code) à import(à l'importation du module) à new(instanciation d'objet) à DESTROY(destruction d'objet) à END(sortie de programme)

Les fonctions sont des citoyens de première classe - tout comme en Perl

Bloquer la portée et la fermeture - Perl a les deux

Appeler indirectement des méthodes et des accesseurs via une variable - Perl le fait aussi:

my $method = 'foo';
my $obj = My::Class->new();
$obj->$method( 'baz' ); # calls $obj->foo( 'baz' )

Définir des méthodes par le code - Perl le permet aussi :

*foo = sub { print "Hello world" };

Documentation en ligne omniprésente - La documentation Perl est en ligne et probablement sur votre système aussi

Méthodes magiques qui sont appelées chaque fois que vous appelez une fonction "inexistante" - Perl l'implémente dans la fonction AUTOLOAD

Références symboliques - il est conseillé de ne pas en tenir compte. Ils mangeront vos enfants. Mais bien sûr, Perl vous permet d'offrir à vos enfants des démons assoiffés de sang.

Échange de valeurs sur une ligne - Perl permet l'affectation de listes

Possibilité de remplacer même les fonctions de base par vos propres fonctionnalités

use subs 'unlink'; 
sub unlink { print 'No.' }

ou

BEGIN{
    *CORE::GLOBAL::unlink = sub {print 'no'}
};

unlink($_) for @ARGV

Je suis fan de la documentation de Perl par rapport à d'autres langages, mais je pense toujours que pour les expressions régulières et les références, cela pourrait être beaucoup rationalisé. par exemple, le meilleur amorce pour les expressions régulières n'est pas Perlre, mais Perlop
John Ferguson

9
"La seule chose que Perl ne peut pas faire est d'avoir des URL arbitraires nues dans votre code, car l'opérateur // est utilisé pour les expressions régulières." - c'est un non-sens absolu.

Merci pour votre perspicacité.J'ai cherché des moyens d'avoir une URL http: // ... nue en code Perl sans utiliser de filtre source, et je n'ai pas trouvé de moyen.Peut-être pouvez-vous montrer comment cela est possible? // est utilisé pour les expressions régulières dans les versions Perl jusqu'à 5.8.x.Dans 5.10, il est réutilisé pour une affectation définie ou définie.
Corion

8
Pourquoi / où voulez - vous voulez des URL nues dans votre code? Je ne peux pas penser à un exemple.
naufragé

18
Personne ne voudrait ça, c'est juste un mème Java. " foo.com " est l'étiquette http: puis "foo.com" dans un commentaire. Certaines personnes trouvent cela intéressant parce que ... elles sont stupides.
jrockway

35

Autovivification . AFAIK aucune autre langue ne l'a .


Je n'avais aucune idée que Python, et al, ne supportaient pas cela.
skiphoppy

@davidnicol: Vraiment? Pouvez-vous fournir un lien? Ma recherche rapide sur google n'a rien retourné. Pour ceux qui ne connaissent pas ECMAscript est le nom correct de Javascript. en.wikipedia.org/wiki/ECMAScript
JJ

1
Et il y a un module pour désactiver l'autovivication
Alexandr Ciornii

1
@Gregg Lind - Étant donné que Python crée automatiquement des variables chaque fois que vous les affectez pour la première fois, l'autovivification créerait des problèmes monstrueux à partir d'une seule faute de frappe.
Chris Lutz

3
@tchrist - a = [[x * y pour y dans xrange (1,11)] pour x dans xrange (1,11)]
Omnifarious

31

Il est simple de citer presque n'importe quel type de chaîne étrange en Perl.

my $url = q{http://my.url.com/any/arbitrary/path/in/the/url.html};

En fait, les différents mécanismes de cotation en Perl sont assez intéressants. Les mécanismes de citation de type regex Perl vous permettent de tout citer, en spécifiant les délimiteurs. Vous pouvez utiliser presque n'importe quel caractère spécial comme #, /, ou ouvrir / fermer des caractères comme (), [] ou {}. Exemples:

my $var  = q#some string where the pound is the final escape.#;
my $var2 = q{A more pleasant way of escaping.};
my $var3 = q(Others prefer parens as the quote mechanism.);

Mécanismes de devis:

q: guillemet littéral; seul le caractère qui doit être échappé est le caractère de fin. qq: une citation interprétée; traite les variables et les caractères d'échappement. Idéal pour les chaînes que vous devez citer:

my $var4 = qq{This "$mechanism" is broken.  Please inform "$user" at "$email" about it.};

qx: fonctionne comme qq, mais l'exécute ensuite en tant que commande système, de manière non interactive. Renvoie tout le texte généré à partir de la sortie standard. (La redirection, si prise en charge dans le système d'exploitation, sort également) Également faite avec des guillemets (le caractère `).

my $output  = qx{type "$path"};      # get just the output
my $moreout = qx{type "$path" 2>&1}; # get stuff on stderr too

qr: interprète comme qq, mais le compile ensuite comme une expression régulière. Fonctionne également avec les différentes options de l'expression régulière. Vous pouvez maintenant passer l'expression régulière en tant que variable:

sub MyRegexCheck {
    my ($string, $regex) = @_;
    if ($string)
    {
       return ($string =~ $regex);
    }
    return; # returns 'null' or 'empty' in every context
}

my $regex = qr{http://[\w]\.com/([\w]+/)+};
@results = MyRegexCheck(q{http://myurl.com/subpath1/subpath2/}, $regex);

qw: Un opérateur de devis très, très utile. Transforme un ensemble de mots séparés par des espaces entre guillemets en une liste. Idéal pour remplir des données dans un test unitaire.


   my @allowed = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z { });
   my @badwords = qw(WORD1 word2 word3 word4);
   my @numbers = qw(one two three four 5 six seven); # works with numbers too
   my @list = ('string with space', qw(eight nine), "a $var"); # works in other lists
   my $arrayref = [ qw(and it works in arrays too) ]; 

Ils sont parfaits pour les utiliser chaque fois que cela rend les choses plus claires. Pour qx, qq et q, j'utilise très probablement les opérateurs {}. L'habitude la plus courante des personnes utilisant qw est généralement l'opérateur (), mais parfois vous voyez aussi qw //.


1
J'utilise parfois qw "" pour que les surligneurs de syntaxe le mettent en évidence correctement.
Brad Gilbert

Fonctionne pour moi dans SlickEdit. :)
Robert P

1
@fengshaun, Les éditeurs que j'utilise généralement les mettent en évidence correctement. Je faisais référence, en partie, au surligneur de syntaxe sur StackOverflow.
Brad Gilbert

@Brad Gilbert: Stack Overflow ne peut pas (enfin, (ne) pas analyser Perl vaut bien s'accroupir. ☹
tchrist

my $moreout = qx{type "$path" 2>&1};... je ne savais pas que tu pouvais faire ça! [TM]
dland

27

Pas vraiment caché, mais de nombreux programmeurs Perl ne connaissent pas le CPAN . Cela s'applique particulièrement aux personnes qui ne sont pas des programmeurs à plein temps ou qui ne programment pas en Perl à plein temps.


27

L'instruction "for" peut être utilisée de la même manière que "with" est utilisé en Pascal:

for ($item)
{
    s/&‎nbsp;/ /g;
    s/<.*?>/ /g;
    $_ = join(" ", split(" ", $_));
}

Vous pouvez appliquer une séquence d'opérations s ///, etc. à la même variable sans avoir à répéter le nom de la variable.

REMARQUE: l'espace insécable ci-dessus (& nbsp;) a caché Unicode pour contourner le Markdown. Ne le copiez pas, collez-le :)


Et "map" fait aussi la même chose ... map {....} $ item; Un avantage d'utiliser "for" sur "map" serait que vous pourriez utiliser next pour sortir.
draegtun

2
De plus, l'élément en cours de manipulation est répertorié avant que le code ne le manipule, ce qui améliore la lisibilité.
Robert P

@RobertP: C'est tout à fait vrai. Un topicalizer est utile dans le discours.
tchrist

26

L'opérateur quoteword est l'une de mes choses préférées. Comparer:

my @list = ('abc', 'def', 'ghi', 'jkl');

et

my @list = qw(abc def ghi jkl);

Beaucoup moins de bruit, plus agréable pour les yeux. Une autre chose vraiment intéressante à propos de Perl, qui manque vraiment lors de l'écriture de SQL, est qu'une virgule de fin est légale:

print 1, 2, 3, ;

Cela semble étrange, mais pas si vous indentez le code d'une autre manière:

print
    results_of_foo(),
    results_of_xyzzy(),
    results_of_quux(),
    ;

L'ajout d'un argument supplémentaire à l'appel de fonction ne vous oblige pas à manipuler des virgules sur les lignes précédentes ou de fin. Le changement de ligne unique n'a aucun impact sur ses lignes environnantes.

Cela rend très agréable le travail avec des fonctions variadiques. C'est peut-être l'une des fonctionnalités les moins appréciées de Perl.


2
Un cas intéressant de la syntaxe de Perl est que ce qui suit est valide: for $ _ qw (une liste de choses) {...}
éphémère

1
Vous pouvez même abuser de la syntaxe globale pour citer des mots, tant que vous n'utilisez pas de caractères spéciaux comme *? Vous pouvez donc écrirefor (<a list of stuff>) { ... }
moritz

1
@ephemient: presque. Cela ne fonctionne qu'avec les lexicaux: for my $ x qw (abc) {...} Par exemple: for $ _ qw (abc) {print} # n'imprime rien
dland

pourquoi ajouter ce lexical supplémentaire lorsque vous pouvez profiter de la valeur par défaut préférée de perl? pour (qw / abcd /) {print; }
fengshaun

2
@ephemient, @fengshaun, @moritz, @dland: C'est «corrigé» dans le blead ; voir ce fil de discussion p5p .
tchrist

26

La possibilité d'analyser les données directement collées dans un bloc DATA . Pas besoin d'enregistrer dans un fichier de test à ouvrir dans le programme ou similaire. Par exemple:

my @lines = <DATA>;
for (@lines) {
    print if /bad/;
}

__DATA__
some good data
some bad data
more good data 
more good data 

Et très utile dans les petits tests!
fengshaun

@peter mortensen comment auriez-vous plusieurs blocs? Et comment terminer un bloc?
Toad

@Toad: c'est la réponse d'Allan (voir la liste des révisions). Il vaut mieux s'adresser à cet utilisateur. Ou, comme cet utilisateur a quitté Stack Overflow, peut-être ne s'adresser à personne en particulier (pour qu'un véritable expert Perl puisse le redresser plus tard).
Peter Mortensen

3
@Hai: Non, ce n'est pas moche - en fait, c'est précisément le contraire de moche: c'est propre, svelte, minimal et beau; en un mot, c'est merveilleux, et les langues sans lui sont un PITA. @peter mortensen, @toad: Une réponse à la façon d'avoir plusieurs blocs de données dans le même programme est d'utiliser le module Inline :: Files hors CPAN.
tchrist

Inline :: Files est implémenté à l'aide de filtres source. Il existe également Data :: Section qui fournit plusieurs blocs en ligne et n'utilise pas de filtres source.
Prakash K

24

Nouvelles opérations de bloc

Je dirais que la possibilité d'élargir le langage, de créer des opérations de pseudo bloc en est une.

  1. Vous déclarez le prototype d'un sous-marin en indiquant qu'il prend d'abord une référence de code:

    sub do_stuff_with_a_hash (&\%) {
        my ( $block_of_code, $hash_ref ) = @_;
        while ( my ( $k, $v ) = each %$hash_ref ) { 
            $block_of_code->( $k, $v );
        }
    }
  2. Vous pouvez alors l'appeler dans le corps comme ça

    use Data::Dumper;
    
    do_stuff_with_a_hash {
        local $Data::Dumper::Terse = 1;
        my ( $k, $v ) = @_;
        say qq(Hey, the key   is "$k"!);
        say sprintf qq(Hey, the value is "%v"!), Dumper( $v );
    
    } %stuff_for
    ;

( Data::Dumper::Dumperest un autre joyau semi-caché.) Remarquez que vous n'avez pas besoin du submot - clé devant le bloc ou de la virgule avant le hachage. Cela finit par ressembler beaucoup à:map { } @list

Filtres sources

Il existe également des filtres source. Où Perl vous transmettra le code pour que vous puissiez le manipuler. Cela, et les opérations de blocage, sont à peu près ce type de choses à ne pas essayer à la maison.

J'ai fait des choses intéressantes avec les filtres de source, par exemple créer un langage très simple pour vérifier l'heure, autorisant de courts one-liners Perl pour certaines prises de décision:

perl -MLib::DB -MLib::TL -e 'run_expensive_database_delete() if $hour_of_day < AM_7';

Lib::TL rechercherait simplement les "variables" et les constantes, les créerait et les remplacerait si nécessaire.

Encore une fois, les filtres sources peuvent être désordonnés, mais ils sont puissants. Mais ils peuvent gâcher les débogueurs quelque chose de terrible - et même les avertissements peuvent être imprimés avec les mauvais numéros de ligne. J'ai arrêté d'utiliser Damian's Switch car le débogueur perdrait toute capacité à me dire où j'étais vraiment. Mais j'ai trouvé que vous pouvez minimiser les dommages en modifiant de petites sections de code, en les gardant sur la même ligne.

Crochets de signal

C'est assez souvent fait, mais ce n'est pas si évident. Voici un gestionnaire de matrices qui s'appuie sur l'ancien.

my $old_die_handler = $SIG{__DIE__};
$SIG{__DIE__}       
    = sub { say q(Hey! I'm DYIN' over here!); goto &$old_die_handler; }
    ;

Cela signifie que chaque fois qu'un autre module du code veut mourir, il doit venir à vous (à moins que quelqu'un d'autre ne fasse un écrasement destructeur $SIG{__DIE__}). Et vous pouvez être averti que quelqu'un pense que quelque chose est une erreur.

Bien sûr, pour suffisamment de choses, vous pouvez simplement utiliser un END { }bloc, si tout ce que vous voulez faire est de nettoyer.

overload::constant

Vous pouvez inspecter les littéraux d'un certain type dans les packages qui incluent votre module. Par exemple, si vous utilisez ceci dans votre importsous-marin:

overload::constant 
    integer => sub { 
        my $lit = shift;
        return $lit > 2_000_000_000 ? Math::BigInt->new( $lit ) : $lit 
    };

cela signifiera que chaque entier supérieur à 2 milliards dans les packages appelants sera changé en Math::BigIntobjet. (Voir surcharge :: constante ).

Littéraux entiers groupés

Pendant que nous y sommes. Perl vous permet de diviser de grands nombres en groupes de trois chiffres et d'en tirer un entier analysable. Remarque 2_000_000_000ci-dessus pour 2 milliards.


5
Lorsque vous utilisez les gestionnaires $ SIG { DIE }, il est fortement recommandé d'inspecter $ ^ S pour voir si votre programme est en train de mourir, ou s'il lance simplement une exception qui va être interceptée. Habituellement, vous ne voulez pas interférer avec ce dernier.
pjf

Le nouveau bloc est très instructif! Je pensais que c'était un langage sémantique! Merci beaucoup.
ZeroCool

Une utilisation instructive du filtre source est NiceSlice de pdl ( pdl.perl.org/?docs=NiceSlice&title=PDL::NiceSlice ) afin que l'on n'ait pas besoin d'utiliser le ->slicecomme méthode à chaque fois qu'une tranche est nécessaire.
Joel Berger

24

Le binaire "x" est l' opérateur de répétition :

print '-' x 80;     # print row of dashes

Cela fonctionne également avec les listes:

print for (1, 4, 9) x 3; # print 149149149

C'est l'une des raisons pour lesquelles Perl a été si populaire auprès des pirates. perl -e 'affiche 0x000 x 25';
JJ

4
Mon utilisation préférée pour cela est de générer des espaces réservés pour la dernière partie d'une instruction SQL INSERT: @p = ('?') X $ n; $ p = rejoindre (",", @p); $ sql = "INSÉRER ... VALEURS ($ p)";
skiphoppy

24

Vérification des traces. Avec la vérification des altérations activée, perl mourra (ou avertira, avec -t) si vous essayez de transmettre des données corrompues (en gros, des données extérieures au programme) à une fonction non sécurisée (ouvrir un fichier, exécuter une commande externe, etc.). Il est très utile lors de l'écriture de scripts setuid ou de CGI ou de tout autre élément où le script a des privilèges plus importants que la personne qui alimente ses données.

La magie va. goto &subfait un appel de queue optimisé.

Le débogueur.

use strictet use warnings. Ceux-ci peuvent vous éviter de nombreuses fautes de frappe.


1
Pourquoi les autres langues n'ont-elles pas cette fonctionnalité? Cette fonctionnalité utilisée rend les scripts Web Perl d'un ordre de grandeur plus sûrs.
Matthew Lock

22

En fonction de la façon dont les commutateurs "-n"et "-p"sont implémentés dans Perl 5, vous pouvez écrire un programme apparemment incorrect comprenant }{:

ls |perl -lne 'print $_; }{ print "$. Files"'

qui est converti en interne en ce code:

LINE: while (defined($_ = <ARGV>)) {
    print $_; }{ print "$. Files";
}

@martin clayton: Pourquoi ça s'appelle ça?
tchrist

@tchrist - parce que cela, soi-disant, ressemble à deux personnes se frottant le nez. De profil, si vous voyez ce que je veux dire.
martin clayton

18

Commençons facilement avec l' opérateur de vaisseau spatial .

$a = 5 <=> 7;  # $a is set to -1
$a = 7 <=> 5;  # $a is set to 1
$a = 6 <=> 6;  # $a is set to 0

1
@Leon: C / C ++ ne fait pas de retour de 3 valeurs pour les nombres. Si la mémoire est bonne, les fonctions String comapre sont le seul retour de 3 valeurs que je connaisse dans tout le langage STL. AFAIK Python n'a pas de comparaison numérique à 3 retours. Java n'a pas non plus de comparaison de retour spécifique au nombre 3.
JJ

7
Cela vaut la peine de mentionner ce qui est si utile à propos des opérateurs de comparaison -1/0/1, car tout le monde ne le sait peut-être pas: vous pouvez les chaîner avec l'opérateur or pour faire primaire / secondaire / etc. sortes. Donc, ($a->lname cmp $b->lname) || ($a->fname cmp $b->fname)trie les personnes par leur nom de famille, mais si deux personnes ont le même nom de famille, elles seront classées par leur prénom.
hobbs

@JJ Python a une comparaison à 3 valeurs: cmp () >>> print (cmp (5,7), cmp (6,6), cmp (7,5)) (-1, 0, 1)
bukzor

18

C'est une méta-réponse, mais les archives de Perl Tips contiennent toutes sortes d'astuces intéressantes qui peuvent être réalisées avec Perl. L'archive des conseils précédents est en ligne pour la navigation et peut être abonnée via une liste de diffusion ou un flux atom.

Certains de mes conseils préférés incluent la création d'exécutables avec PAR , l' utilisation d'autodie pour lancer automatiquement des exceptions , et l'utilisation des constructions switch et smart-match dans Perl 5.10.

Divulgation: Je suis l'un des auteurs et mainteneurs de Perl Tips, donc je leur accorde évidemment une très grande importance. ;)


2
C'est probablement l'un des langages les mieux documentés sur le marché et définit le modèle pour les outils de recherche de documentation. Que la liste dans cette question n'est probablement pas aussi nécessaire que pour d'autres langues.
Axeman

1
autodie est très jolie.
j_random_hacker

18

map - non seulement parce que cela rend le code plus expressif, mais parce que cela m'a donné envie de lire un peu plus sur cette "programmation fonctionnelle".


15

La clause continue sur les boucles. Elle sera exécutée au bas de chaque boucle, même celles qui sont les suivantes.

while( <> ){
  print "top of loop\n";
  chomp;

  next if /next/i;
  last if /last/i;

  print "bottom of loop\n";
}continue{
  print "continue\n";
}

15

Mon vote irait pour les groupes (? {}) Et (?? {}) dans les expressions régulières de Perl. Le premier exécute le code Perl, ignorant la valeur de retour, le second exécute le code, en utilisant la valeur de retour comme expression régulière.


perl a inventé tellement d'extensions de regexp que d'autres programmes utilisent maintenant souvent pcre (regex compatible perl) au lieu du langage regex original.
Sec


Perl a vraiment (autant que je sache), en tête du peloton en ce qui concerne les expressions rationnelles.
Brad Gilbert

Ceci, pour autant que je sache, est encore expérimental et peut ne pas fonctionner de la même manière dans les futurs Perls. Pour ne pas dire que ce n'est pas utile, mais une version légèrement plus sûre et tout aussi utilisable peut être trouvée dans le drapeau / e de la commande s ///: s/(pattern)/reverse($1);/ge;# inverse tout patterns.
Chris Lutz

@Chris Lutz, @Leon Timmerman: Notez que ces deux constructions sont maintenant réëntrantes. Notez également que le second n'a plus besoin d'être utilisé pour effectuer des modèles récursifs, maintenant que nous pouvons récurer sur les groupes de capture. @Brad Gilbert: C'est vrai, bien que PCRE fasse un travail décent de nous suivre; un domaine d'excellence regex où Perl est totalement incontesté est son accès aux propriétés Unicode; voir ma distribution unitrio de uninames, unicharset surtout unipropspour voir juste une partie de ce que je veux dire.
tchrist

13
while(/\G(\b\w*\b)/g) {
     print "$1\n";
}

l'ancre \ G. Il fait chaud .


3
... et il indique la position de la fin du match précédent.
Dave Sherohman

1
Mais vous devez appeler votre regex dans un contexte scalaire.
davidnicol

@davidnicol: Le code ci-dessus fonctionne. Pouvez-vous clarifier ce que vous voulez dire?
JJ

13

L' m//opérateur a quelques cas spéciaux obscurs:

  • Si vous utilisez ?comme délimiteur, il ne correspond qu'une seule fois, sauf si vous appelez reset.
  • Si vous utilisez 'comme délimiteur, le motif n'est pas interpolé.
  • Si le modèle est vide, il utilise le modèle de la dernière correspondance réussie.

2
Ce sont plus des pièges cachés que des fonctionnalités cachées! Je ne connais personne qui les aime. Un fil sur p5p il y a quelque temps discutait de l'utilité d'un indicateur putatif m / $ foo / r, où / r signifierait pas d'interpolation (la lettre n'est pas importante) puisque personne ne peut jamais se souvenir des guillemets simples.
dland

2
@dland: d'accord; Je dirais que ces cachés MIS caractéristiques et ne jamais les utiliser dans le code de production.
Michael Carman

7
Je ne peux pas imaginer qu'un programmeur Perl soit incapable de se souvenir (ou même de deviner) que les guillemets simples représentent aucune interpolation. Son utilisation avec cette sémantique est presque universelle dans le langage que je préfère m'attendre à ce que ce soit le cas ...
sundar - Rétablir Monica

et si le modèle est vide et que la dernière correspondance réussie a été compilée avec le modificateur / o, à partir de là, il restera bloqué sur ce modèle.
davidnicol

1
Je pense que le comportement de modèle vide est obsolète. Principalement parce qu'un motif comme m / $ foo / devient un vilain bogue quand $ foo est vide.
Matthew S

12

L' opérateur losange de descripteur de fichier nul <>a sa place dans la création d'outils de ligne de commande. Il agit comme <FH>lire à partir d'une poignée, sauf qu'il sélectionne comme par magie celui qui est trouvé en premier: les noms de fichiers de ligne de commande ou STDIN. Tiré de perlop:

while (<>) {
...         # code for each line
}

4
Il suit également la sémantique UNIX de l'utilisation de "-" pour signifier "lire à partir de stdin. Vous pourriez donc le faire perl myscript.pl file1.txt - file2.txt, et perl traiterait le premier fichier, puis stdin, puis le deuxième fichier.
Ryan C. Thompson

Vous pouvez overloadl' <>opérateur sur vos propres objets ( <$var>) pour fonctionner comme un itérateur. Cependant, cela ne fonctionne pas comme on pouvait s'y attendre dans le contexte d'une liste.
dolmen

11

Blocs de code spéciaux tels que BEGIN, CHECKetEND . Ils viennent d'Awk, mais fonctionnent différemment en Perl, car ils ne sont pas basés sur des enregistrements.

Le BEGINbloc peut être utilisé pour spécifier du code pour la phase d'analyse; il est également exécuté lorsque vous effectuez la vérification de la syntaxe et des variables perl -c. Par exemple, pour charger des variables de configuration:

BEGIN {
    eval {
        require 'config.local.pl';
    };
    if ($@) {
        require 'config.default.pl';
    }
}

11
rename("$_.part", $_) for "data.txt";

renomme data.txt.part en data.txt sans avoir à me répéter.


10

Un peu obscur est "l'opérateur" tilde-tilde qui force le contexte scalaire.

print ~~ localtime;

est le même que

print scalar localtime;

et différent de

print localtime;

5
Ceci est particulièrement obscur car perl5.10.0 introduit également l '«opérateur de correspondance intelligente» ~~, qui peut faire des correspondances regex, peut vérifier si un élément est contenu dans un tableau et ainsi de suite.
moritz

Ce n'est pas obscur, c'est obscur (et utile pour le golf et les JAPH).
Michael Carman

Ce n'est pas correct! ~~ n'est pas sûr sur les références! Il les stringifie.
Leon Timmermans

Hé bien oui. La stringification est ce qui arrive aux références lorsqu'elles sont forcées dans un contexte scalaire. Comment cela rend-il "~~ force le contexte scalaire" incorrect?
Dave Sherohman

3
@Nomad Dervish: contexte scalaire / = stringification. par exemple "$ n = @a" est un contexte scalaire. "$ s = qq '@ a'" est une stringification. En ce qui concerne les références, "$ ref1 = $ ref2" est un contexte scalaire, mais ne stringify pas.
Michael Carman


9

Le "mode de désespoir" des constructions de contrôle de boucle de Perl qui les amène à rechercher la pile pour trouver une étiquette correspondante autorise certains comportements curieux dont Test :: More profite, pour le meilleur ou pour le pire.

SKIP: {
    skip() if $something;

    print "Never printed";
}

sub skip {
    no warnings "exiting";
    last SKIP;
}

Il y a le fichier .pmc peu connu. «use Foo» recherchera Foo.pmc dans @INC avant Foo.pm. Cela visait à permettre le chargement du bytecode compilé en premier, mais Module :: Compile en profite pour mettre en cache les modules filtrés par la source pour des temps de chargement plus rapides et un débogage plus facile.

La possibilité de transformer les avertissements en erreurs.

local $SIG{__WARN__} = sub { die @_ };
$num = "two";
$sum = 1 + $num;
print "Never reached";

C'est ce à quoi je peux penser du haut de ma tête qui n'a pas été mentionné.


9

L'opérateur de la chèvre *:

$_ = "foo bar";
my $count =()= /[aeiou]/g; #3

ou

sub foo {
    return @_;
}

$count =()= foo(qw/a b c d/); #4

Cela fonctionne car l'affectation de liste dans un contexte scalaire produit le nombre d'éléments de la liste en cours d'affectation.

* Remarque, pas vraiment un opérateur


C'est le plus (enfin, le moins) beau "opérateur" qui soit.
Chris Lutz
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.