Existe-t-il une expression régulière compatible Perl permettant de réduire les espaces des deux côtés d'une chaîne?

StackOverflow https://stackoverflow.com/questions/184590

  •  06-07-2019
  •  | 
  •  

Question

Y a-t-il un moyen de faire cela en une seule ligne?

$x =~ s/^\s+//;
$x =~ s/\s+$//;

En d'autres termes, supprimez tous les espaces de début et de fin d'une chaîne.

Était-ce utile?

La solution

$x =~ s/^\s+|\s+$//g;

ou

s/^\s+//, s/\s+$// for $x;

Autres conseils

Ma première question est ... pourquoi? Je ne vois aucune des solutions utilisant une seule expression rationnelle plus lisibles que l’expression rationnelle avec laquelle vous avez commencé. Et ils ne sont pas loin d'être aussi rapides.

#!/usr/bin/perl

use strict;
use warnings;

use Benchmark qw(:all);

my $a = 'a' x 1_000;

my @x = (
         "    $a   ",
         "$a   ",
         $a,
         "    $a"
        );

cmpthese(-5,
         {
             single => sub {
                 for my $s (@x)
                 {
                     my $x = $s;
                     $x =~ s/^\s+|\s+$//g;
                 }
             },
             double => sub {
                 for my $s (@x)
                 {
                     my $x = $s;
                     $x =~ s/^\s+//;
                     $x =~ s/\s+$//;
                 }
             },
             trick => sub {
                 for my $s (@x)
                 {
                     my $x = $s;
                     s/^\s+//, s/\s+$// for $x;
                 }
             },
             capture => sub {
                 for my $s (@x)
                 {
                     my $x = $s;
                     $x =~ s/\A\s*(.*?)\s*\z/$1/
                 }
             },
             kramercap => sub {
                 for my $s (@x)
                 {
                     my $x = $s;
                     ($x) = $x =~ /^\s*(.*?)\s*$/
                 }
             },
         }
        );

donne les résultats sur ma machine de:

             Rate    single   capture kramercap     trick    double
single     2541/s        --      -12%      -13%      -96%      -96%
capture    2902/s       14%        --       -0%      -95%      -96%
kramercap  2911/s       15%        0%        --      -95%      -96%
trick     60381/s     2276%     1981%     1974%        --       -7%
double    65162/s     2464%     2145%     2138%        8%        --

Modifier : runrig a raison, mais peu de changement. J'ai mis à jour le code pour copier la chaîne avant modification, ce qui ralentit bien sûr les choses. J'ai également pris en compte la suggestion de brian d foy dans une autre réponse consistant à utiliser une chaîne plus longue (bien qu'un million semblait excessif). Cependant, cela suggère également qu'avant de choisir le style d'astuce, vous devez déterminer la longueur de votre chaîne - les avantages de l'astuce sont atténués avec des chaînes plus courtes. Cependant, à toutes les longueurs que j'ai testées, le double gagne. Et c'est toujours plus facile pour les yeux.

Tanktalus montre une référence pour les très petites chaînes, mais les problèmes s’aggravent à mesure que les chaînes grossissent. Dans son code, j'ai changé la partie supérieure:

my $a = 'a' x 1_000_000;

my @x = (
  "   $a   ",
  "$a    ",
  $a,
  "    $a"
  );

Je reçois ces résultats:

          Rate  single capture   trick  double
single  2.09/s      --    -12%    -98%    -98%
capture 2.37/s     13%      --    -98%    -98%
trick   96.0/s   4491%   3948%      --     -0%
double  96.4/s   4512%   3967%      0%      --

À mesure que la chaîne grossit, utilisez " astuce ". et " double " sont presque les mêmes, et la solution commune que la plupart des gens vont chercher, le "single" (y compris moi, parce que je ne peux pas rompre cette habitude même si je le sais bien), commence vraiment à craquer.

Chaque fois que vous regardez un point de repère, réfléchissez à ce qu’il vous dit. Pour voir si vous le comprenez, modifiez les données et réessayez. Faites des tableaux longs, des scalaires grands, etc. Faites des boucles, des greps ou des regex pour trouver des éléments au début, au milieu et à la fin. Voyez si les nouveaux résultats correspondent à votre prédiction. Déterminez quelle est la tendance. Les performances s'améliorent-elles, approchent-elles d'une limite, commencent-elles alors à baisser, ou autre chose?

C'est drôle, vous devriez en parler!

J'ai récemment lu un article analysant les performances de douze (!) mises en œuvre de trim différentes! .

Bien que l'article utilise spécifiquement l'implémentation de regex JavaScript, il utilise la syntaxe Perl, je pense donc que c'est à propos de cette discussion.

Se disputer avec l'hérétique, pourquoi le faire? Toutes les solutions ci-dessus sont "correctes". en ce sens qu'ils coupent les espaces des deux côtés de la chaîne en une seule passe, mais qu'aucun n'est terriblement lisible (attendez-vous peut-être celui-ci ). À moins que l'audience de votre code ne soit composée de codeurs Perl de niveau expert, chacun des candidats ci-dessus doit avoir un commentaire décrivant ce qu'il fait (probablement une bonne idée de toute façon). En revanche, ces deux lignes accomplissent la même chose sans utiliser de symboles de tête, de joker, de code dichlore ou tout autre élément qui ne semble pas immédiatement évident pour un programmeur expérimenté:

$string =~ s/^\s+//;
$string =~ s/\s+$//;

Il y a (sans doute) un impact négatif sur les performances, mais tant que vous n'êtes pas concerné par quelques microsecondes à l'exécution, la lisibilité en vaut la peine. IMHO.

Voilà: $ x = ~ s / \ A \ s * (. *?) \ s * \ z / $ 1 /;

$ x = ~ s / (^ \ s +) | (\ s + $) // g;

Je le fais habituellement comme ça:

($foo) = $foo =~ /^\s*(.*?)\s*$/;

Tout ce qui se trouve entre les espaces de début et de fin est regroupé et renvoyé, je peux donc l'affecter à la même ancienne variable.

Ou ceci: s / \ A \ s * | \ s * \ Z // g

s/^\s*(\S*\S)\s*$/$1/
$var1 =~ s/(^\s*)(.*?)(\s*$)+/$2/;
$x =~ s/^\s*(.*?)\s*$/$1/;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top