Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1894 connectés 

  FORUM HardWare.fr
  Programmation
  Shell/Batch

  Sed, remplacer les n premières occurrences

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Sed, remplacer les n premières occurrences

n°2054975
ptitchep
Posté le 07-02-2011 à 22:47:22  profilanswer
 

Bonjour,
 
Comme dit dans le titre, je cherche à remplacer les n premières occurrences d'un caractère donné d'une ligne par un autre.
Exemple pour les 4 premiers et a => b:
laaaaaal => lbbbbaal
lalalalalalala =>lblblblblalala
 
Google! ou man! me direz vous... Je ne trouve que ceci:
 
replace/substitute the N first occurences of each line
sed 's/<replaceThis>/<withThis>/<N>' <file>
 
Très bien, sauf que chez moi:

Citation :

chep@Ludwig:~$ echo laaaaal |sed 's/a/b/2'
labaaal

Seule la deuxième occurrence est remplacée
 
J'ai aussi une petite question subsidiaire  :ange:  
Comment remplacer par exemple 4 'a' par 3 'b'? J'arrive a détecter les '4' a mais pas à remplacer par 3 'b'.
 

Citation :

chep@Ludwig:~$ echo laaaal |sed 's/a\{4\}/b/'
lbl


mais

Citation :

chep@Ludwig:~$ echo laaaal |sed 's/a\{4\}/b\{3\}/'
lb{3}l


Évidemment, dans mon cas il suffit d'écrire 'bbb' mais le but serait plutôt d'utiliser une variable pour remplacer n 'a' par m 'b'.
 
 
Merci d'avance.


---------------
deluser --remove-home ptitchep
mood
Publicité
Posté le 07-02-2011 à 22:47:22  profilanswer
 

n°2055382
ptitchep
Posté le 09-02-2011 à 14:26:45  profilanswer
 

Personne? :(


---------------
deluser --remove-home ptitchep
n°2055478
billgatesa​nonym
Posté le 09-02-2011 à 15:48:46  profilanswer
 

Une solution serait de faire une boucle jusqu'à ce que le nombre de remplacement soit atteint ou que la fin de fichier soit atteinte.
A l'intérieur de la boucle, on ferait la recherche et le remplacement pour chaque ligne.
 
La boucle ferait une lecture du fichier de manière classique par :

cat thefichier.txt | while read theligne
do
   ...
done

Ou bien on peut utiliser awk ou gawk ou nawk.
 
On doit aussi pouvoir utiliser Perl ou d'autres langages. Personnellement, j'écrirais un petit code en C, compilé avec gcc, et le problème aurait été résolu en beaucoup moins de temps qu'il n'en aura fallu pour poster la question sur le forum et attendre la première réponse.

n°2055651
ptitchep
Posté le 10-02-2011 à 02:08:41  profilanswer
 

Merci,
Cela permet de traiter chaque ligne du fichier, mais ça ne permet pas de remplacer les N premières occurrences de chaque ligne. À moins de faire encore une boucle pour chaque ligne, mais quand on m'a vendu sed, on m'a dit qu'il était beaucoup plus puissant :(


---------------
deluser --remove-home ptitchep
n°2055715
Nukolau
Posté le 10-02-2011 à 10:58:49  profilanswer
 

Je viens de jeter  un oeil au man, et le chiffre qu'on peux mettre à la fin c'est pour remplacer la n-ième occurrence, pas le nombre d'occurrences à remplacer.  
 
Visiblement il n'y a pas moyen non plus de faire comme le cut avec un truc du genre 1-4 :(
 
awk doit pouvoir te permettre de réaliser ca, mais mes connaissances en awk sont assez limitées...

n°2055732
gilou
Modérateur
Modzilla
Posté le 10-02-2011 à 11:32:20  profilanswer
 

C'est très probablement faisable en sed, mais ça demande un niveau d'expertise que j'ai eu il y a bien longtemps, mais que je n'ai plus depuis que j'utilise perl, parce que ça doit être assez complexe à écrire en sed et plus simple en perl.
En perl je procéderais ainsi:
s/(a+)/{my $tmp = substr($1, 1); $tmp =~ tr!a!b!; $tmp}/eg;
On cherche le pattern a+, quand trouvé, on évalue (le e de /eg) {my $tmp = substr($1, 1); $tmp =~ tr!a!b!; $tmp}:
On récupère la sous chaine matchant le pattern (donc avec au moins un a) commençant au 2e caractère, donc ca fait la chaine avec un a de moins, on remplace les a par des b dans cette sous chaine, et enfin on renvoie la chaine (comme on est dans un eval, pas besoin de return...)
C'est donc le résultat de cette évaluation qui est substitué.

 

Testé ainsi:

Code :
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. my $x = "Biaaall the bad caaaaaat";
  6. $x =~ s/(a+)/{my $tmp = substr($1, 1); $tmp =~ tr!a!b!; $tmp}/eg;
  7. print $x, "\n";

>perl test.pl
>Bibbll the bd cbbbbbt

 

Bon ensuite l'intérêt, c'est qu'on peut en faire une procédure, plus modulaire et réemployable:

Code :
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. # powersubst(chaine, caractere a remplacer, caractere de remplacement, décalage)
  6. #remplace le caractère a remplacer par le caractère de remplacement
  7. # si décalage est positif n'est pas nul on remplace n occurences initiales
  8. # du caractère a remplacer par n + décalage occurences du caractère de remplacement
  9. # ou rien si n + décalage n'est pas positif
  10. sub powersubst {
  11.    my ($_, $cin, $cout, $decal) = @_;
  12.    if ((not defined($decal)) or (not $decal)) {
  13.     s/$cin/$cout/g;
  14.    }
  15.    else {
  16.     if ($decal < 0) {
  17.         s/($cin+)/{my $tmp = substr($1, 0, $decal);  $tmp =~ s!$cin!$cout!g; $tmp}/eg;
  18.     }
  19.     if ($decal > 0) {
  20.         s/($cin+)/{my $tmp = $1.("$cout" x $decal); $tmp =~ s!$cin!$cout!g; $tmp}/eg;
  21.     }
  22.    }
  23.    return $_;
  24. }
  25.  
  26. my $x = "Biaaall the bad caaaaaat";
  27.  
  28. print powersubst($x, "a", "x", 3), "\n\n";
  29. print powersubst($x, "a", "y", 0), "\n\n";
  30. print powersubst($x, "a", "z", -2), "\n\n";
  31. print powersubst($x, "a", "s" ), "\n";

>perl test.pl
>Bixxxxxxll the bxxxxd cxxxx
>
>Biyyyll the byd cyyyyyyt
>
>Bizll the bd czzzzt
>
>Bisssll the bsd csssssst

 

A+,


Message édité par gilou le 10-02-2011 à 13:25:06

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2055738
art_dupond
je suis neuneu... oui oui !!
Posté le 10-02-2011 à 11:38:54  profilanswer
 

Je ne sais pas si c'est "bien" mais
 

Code :
  1. num=3;
  2. echo laaaaal | sed "`s=$( printf "%${num}s" ); echo " ${s// /s:a:b:;}"`"


 
 

Spoiler :

echo laaaaal | sed 's:a:b:;s:a:b:;s:a:b:;'


---------------
oui oui
n°2055792
efimo
Posté le 10-02-2011 à 13:50:57  profilanswer
 

Essais ça:
 

Code :
  1. sed "s/$i/$j/g"


 
puis tu mets tes regex dans les variables.
 
Et si tu veux travailler dans un intervalle précis de lignes tu rajoutes:
 

Code :
  1. sed "$i,$j s/$k/$l/flags"


 
Espérant t'avoir aidé.
 
Edit : L'incrémentation du flags devrait suffire pour définir le nombre d'occurence


Message édité par efimo le 10-02-2011 à 16:38:13

---------------
FeedBack
n°2055800
gilou
Modérateur
Modzilla
Posté le 10-02-2011 à 13:59:54  profilanswer
 

Oui, mais tout ça répond pas a sa question initiale qui est si j'ai bien compris:
comment remplacer les toutes occurrences de n fois le caractère a par m(n) fois le caractère b, ou m dépend de n (par exemple, m(n) = n-1, ou n+1, ...)
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2055844
ptitchep
Posté le 10-02-2011 à 15:33:12  profilanswer
 

Merci à tous,
En fait vous avez répondu à mes deux questions.
 
gilou: en effet c'est puissant la fonction en perl et ça répond à ma question subsidiaire donc intéressant.  
Mon but était de le faire avec sed uniquement par curiosité à la base parce que je cherchais à faire les étoiles de ce post:  
http://forum.hardware.fr/hfr/Progr [...] 2303_1.htm
donc je voulais essayer une technique où j'écrirais le nombre max d'étoiles et je remplace les N premières par des espaces :p


---------------
deluser --remove-home ptitchep
mood
Publicité
Posté le 10-02-2011 à 15:33:12  profilanswer
 

n°2056250
gilou
Modérateur
Modzilla
Posté le 12-02-2011 à 11:00:43  profilanswer
 

ptitchep a écrit :

Mon but était de le faire avec sed uniquement par curiosité à la base parce que je cherchais à faire les étoiles de ce post.
Donc je voulais essayer une technique où j'écrirais le nombre max d'étoiles et je remplace les N premières par des espaces :p

Pour cela, il suffit de remplacer n occurrences de a par n-1 occurrences de b, en perl, le plus simple serait ceci:
1) Remplacer n occurences de a par n-1 occurences de a: s/(a)(\1*)/$2/g; Dans le second groupe, \1 représente ce qui est matché dans le premier groupe
2) remplacer a par b: tr/a/b/

 

Pour le 1, en sed, cela se transpose a priori ainsi: s/\(a\)\(\1*\)/\2/g et pour le 2, s/a/b/g
donc au final sed 's/\(a\)\(\1*\)/\2/g;s/a/b/g'  (testé sous cygwin)

 

On voit tout de suite aussi que pour remplacer n occurrences de a par n-1 occurrences de b, il va suffire de faire
sed 's/\(a\)\(\1*\)/\1\1\2/g;s/a/b/g'  (testé sous cygwin)

 

echo "**********" | sed ':loop p;s/\(\*\)\(\1*\)/ \2/g;t loop;:pool p;s/\( \)\(\1*\)/*\2/;t pool;d'
 :whistle: sans doute améliorable
A+,


Message édité par gilou le 12-02-2011 à 13:53:19

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2057553
ptitchep
Posté le 17-02-2011 à 15:02:34  profilanswer
 

Merci, j'ai appris pas mal sur sed du coup.
En effet ton expression se simplifie mais je poste ça sur l'autre topic.


---------------
deluser --remove-home ptitchep

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Shell/Batch

  Sed, remplacer les n premières occurrences

 

Sujets relatifs
[BATCH/DOS] rechercher/remplacer un ensemble de ligne par d'autres[Batch] Script de comptage du nombre d'occurrences dans un fichier
Js : remplacer du texte au sein de la pageLes premières oppérations d'un développement.
Remplacer un mot qui n'est pas compris entre 2 balisesRemplacer la valeur 0 par un blanc ou tiret
Comment remplacer un caractère dans une très longue listeRemplacer URL par LIEN cliquable via REGEX
Ecire et remplacer caractère dans un fichier txtMoyen le plus simple de modifier/remplacer ?
Plus de sujets relatifs à : Sed, remplacer les n premières occurrences


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR