Bonjour,
J'ai une chaîne de caractères : Lire:des:Histoires:droles
et j'aimerais remplacer uniquement avant le premier deux-points par le mot Ecrire.
Je débute sous Perl, j'ai pensé aux expressions régulières ...
Merci de votre aide.
Bonjour,
J'ai une chaîne de caractères : Lire:des:Histoires:droles
et j'aimerais remplacer uniquement avant le premier deux-points par le mot Ecrire.
Je débute sous Perl, j'ai pensé aux expressions régulières ...
Merci de votre aide.
Quelque chose comme ceci devrait faire l'affaire, mais il faudrait que tu détailles un peu plus ton besoin :
Code : Sélectionner tout - Visualiser dans une fenêtre à part $texte =~ s/^\w(:)/Ecrire$1/;
Après tu peux aussi séparer ta chaine pour les mettre dans un tableau.
Code perl : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 my $chaine="Lire:des:Histoires:droles";#Ta chaine de caractère my @tab=split(/:/,$chaine);#Le caractère de séparation est ":" $tab[0]="Ecrire";#Tu remplaces "Lire" par "Ecrire" print "@tab";#Et tu affiches la nouvelle chaînes de caractère #Cela affiche :"Ecrire Des Histoires droles" <>;
Oui avec un remplacement:(^ marque le début de la chaîne, [^:] est une classe de caractères qui exclue les deux-points, * est un quantificateur qui signifie zéro ou plusieurs fois.)
Code : Sélectionner tout - Visualiser dans une fenêtre à part $txt =~ s/^[^:]*/Ecrire/;
ou en passant par split:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 my @tab = split(/:/, $txt, 2); # le 3e paramètre limite le nombre de résultats à 2 $txt = "Ecrire:" . $tab[1];
Franchement, un split pour quelque chose d'aussi simple à faire avec une expression régulière, c'est un peu de l'overkill.
Si ta chaîne est toujours "Lire:Des:Histoires:Droles"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 my $txt = 'Lire:des:Histoires:droles'; $txt =~ s/Lire/Ecrire/; print $txt;
De l'overkill non, car il n'y a pas de mise en œuvre d'un outil surpuissant ou disproportionné par rapport à la tâche à accomplir, moins straight forward (droit au but) peut être.
Ça peut paraître moins direct parce que moins concis (cela dit on peut l'écrire en une ligne) et parce que les étapes de l'opération sont plus apparentes, mais il ne doit pas y avoir une grande différence entre les deux (recherche, chaînes temporaires, concaténation, affectation du résultat => toutes ces étapes sont bien présentes lors d'une substitution mais la plupart sont masquées).
De plus, dans un contexte de champs séparés par un délimiteur (ici littéral donc trouvé très rapidement par un algorithme de recherche rapide, sans même utiliser la marche normal du moteur), utiliser split n'a rien d'incongru quand bien même le champ visé serait le premier.
À noter que dans tout autre langage que Perl qui fait la part belle au regex, les remarques auraient été plutôt dans l'autre sens (pourquoi sortir les regex quand on peut faire comme ci ou comme ça) avec plus ou moins de raison. Par exemple, si je devais faire la même chose en shell, mise à part l'utilisation du parameter expansion:$txt="Ecrire"${txt#*:} ou $txt=${txt/*([^:]):/Ecrire:} avec Bash qui reste la solution la plus concise, je ne sais pas sur quoi mon choix se serait porté entre cut (je ne sortirais probablement pas awk pour ça) et sed.
En fait, CosmoKnacki, je répondais plutôt à SupraPF qu'à toi. Pour 2 raisons, d'abord tu as aussi proposé une regex, et, après tout TIMTOWTDI. La seconde raison est que tu as utilisé un split avec trois paramètres, le 2 passé en argument permet de ne pas splitter toute la chaîne, et la concaténation finale n'utilise que 2 sous-chaînes. Du coup, ta solution est sans doute efficace. Celle proposée par SupraPF l'était moins (plus de travail au split et plus à la concaténation).
Il m'arrive de "détourner" split de son objet:
Alors qu'une regex ancrée sur la fin de chaîne serait peut-être meilleure:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 my $last_field = (split /;/, $_)[-1];
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 $last_field = $1 if /;(\w+)$/;
Suite à mon dernier post, je me suis livré à quelques benchmarks (avec Benchmark::timethese) pour les deux voies histoire de mesurer l'impact que pouvait avoir le fait d'utiliser une chaîne littérale pour split (et donc de court-circuiter la marche du moteur de regex avec un algorithme de recherche rapide. (Bien sûr, dans la réalité, je doute qu'il y ait besoin de faire plus d'un million de fois le même remplacement. Ça reste des résultats de benchmark sur une chaîne très courte).
Par rapport à une substitution le gain reste certes faible 4 à 5% (Autant dire que pour des remplacements sporadiques c'est imperceptible.), mais il est toujours au rendez-vous, et ce bien que la pattern de substitution soit ancrée au début de la chaîne. Mais il suffit de changer /:/ en /[:§]/ pour que la tendance s'inverse. Par contre changer /:/ en /:d/ ralentit à peine le split, car on reste avec une chaîne littérale.
Du coup, j'ai également tester les deux propositions pour obtenir le dernier champs:Et là, malgré le fait que la pattern de la substitution soit ancrée à droite avec $ (ce qui ne change pas grand chose quand on y pense car le moteur de regex avance de gauche à droite, donc on pourrait mettre (?!choucroute garnie) à la place que ce serait pareil), le split avec sa pattern littérale est 2 à 3 fois plus rapide. Par contre je ne parierai pas sur sa consommation mémoire.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 use Benchmark; use strict; use warnings; my $count = shift || die "Need a count!\n"; sub splitou { my $txt = "C;était;l;hôtel;d;Abyssinie;et;du;Calvados;réunis"; my $last_field = (split /;/, $txt)[-1]; } sub matchou { my $txt = "C;était;l;hôtel;d;Abyssinie;et;du;Calvados;réunis"; my $last_field = $1 if $txt =~ /;([^;]*)$/; } timethese ( $count, {'Method splitou' => '&splitou', 'Method matchou' => '&matchou'}); exit;
Jolie débat cependat j'ai l'impression qu'on perd de vue l'objectif principal qui est :
en lisant celà avec un esprit plus ou moins professionnel, habitué et avec du ecul on recherche à faire des choses dynamique qui sont en fonction de ceci, celà.
Cependant on perd de vu les cose les plus simple. Le problème que pose crow, est un problème qui se trouve dans le tuto perl ($v =~ s/voiture/pieds/; )
J'en déduit que du coup la solution la plus simple pour quelqu'un qui débute en perl serait donc
Mais Jolie débat
Code : Sélectionner tout - Visualiser dans une fenêtre à part $txt =~ s/Lire/Ecrire/;
Je ne suis pas du même avis que toi, magicshark, et je rejoindrais CosmoKnacki. J'explique mes raisons :
- en général, le posteur "débutant" imagine des solutions locales à ses problèmes : ici, les regexp. Cependant il est très rare qu'il ait une vision plus globale de son problème (et notamment, étant débutant, il n'imagine pas toujours les différentes solutions possibles à son problème local). Dans le cas présent, le fait d'avoir une liste de champs séparés par un : (le séparateur), me laisse penser que dans le reste du traitement, on cherchera aussi à utiliser les autres champs (ce n'est pas sûr, mais c'est probable).
- la question soulevée ne semble pas générer de problème de performance (d'ailleurs, "a priori", on ne devrait jamais avoir à se préoccuper des performances, mais se préoccuper d'abord du fonctionnel, et de la maintenabilité).
Du coup, la solution du split (même à 2 paramètres), ne me parait pas du tout inappropriée, et elle est en tout cas
Bonjour,
Pas spécialement pour la perf, mais juste une autre vision pour faire la même chose:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 my $txt = 'Lire:des:Histoires:droles'; $txt = join ":","Ecrire",$txt =~ m/:(.*)/; print $txt;
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager