[Résolu] Sed: extraire une chaîne avec un préfixe optionel

Sed: extraire une chaîne avec un préfixe optionel [Résolu] - Codes et scripts - Linux et OS Alternatifs

Marsh Posté le 06-01-2013 à 10:22:42    

Bonjour,
 
J’essaie depuis un moment de tenter d'extraire une chaîne de caractères avec sed, qui peut éventuellement être précéder d'un préfixe (que je veux garder), mais jusque là, sans succès.
 
Par exemple, avec:
Chaine="sans importance préfixeMaString et une éventuelle suite"
Chaine="sans importance MaString et une autre suite"
j'aimerais un expression qui me sorte "préfixeMaString et une éventuelle suite" et "MaString et une autre suite"
 
Voici la commande autour de laquelle je tourne en rond, avec pleins de variantes, sans toutefois donner de résultats:

Code :
  1. echo "$Chaine" | sed 's/ .* \( \(préfixe\)\? MaString.*\) /\1/'


(j'ai rajouter des espaces pour amélioré la lecture, dans la vrai commande, j'en utilise bien-sûr aucun)
 
Mais celle-ci ne me sort jamais le préfixe quant il y en a un.
Cette autre variante ne marche pas mieux:

Code :
  1. echo "$Chaine" | sed 's/ .* \(préfixe\)\? \(MaString.*\) /\1\2/'


 
En essayant une autre forme:

Code :
  1. echo "$Chaine" | sed 's/ \(.*\) \(\(préfixe\)\? MaString.*\) /\1/'


je me rend compte que mon préfixe fait parti du groupe 1, comme si le '.*' "bouffait" mon préfixe au lieu de le laisser au groupe 2.
 
Est-ce que vous pouvez m'expliquer ce qui ne va pas dans mon expression?
 
Merci


Message édité par wistiti68 le 07-01-2013 à 22:13:36
Reply

Marsh Posté le 06-01-2013 à 10:22:42   

Reply

Marsh Posté le 06-01-2013 à 12:03:22    

Il me semble que le comportement par défaut d'une expression régulière est de matcher le plus loin possible, ensuite quand ça ne matche pas jusqu'au bout, il revient en arrière jusqu'à ce que ça macthe.  
Du coup, comme ton expression autorise que "préfixe" puisse ne pas être dans la seconde partie, ben il matche la seconde expression le plus loin possible (en incluant préfixe), il va jusqu'au bout de la chaine en entrée, se rends compte qu'il ne matche pas la deuxième partie de ton expression, donc revient en arrière caractère par caractère, jusqu'à matcher MaString.*, et du coup c'est bon, toute ton expression est matchée, et il arrête le traitement là, sauf que préfixe a été placé dans la première partie (mais ton expression régulière l'autorise, donc il n'a pas de raison de continuer plus loin).
 
Je sais pas si mon explication est très claire. :D
 
Je pense qu'il faudrait que tu interdises à ta première expression de terminer par "préfixe" et du coup ça devrait être bon.


---------------
Ce n'est point ma façon de penser qui a fait mon malheur, c'est celle des autres.
Reply

Marsh Posté le 06-01-2013 à 14:37:44    

Je te remercie, tu as été très claire, ça m'a débloqué dans mes recherches.
 
Ça ne fait qu'une semaine que je me suis mis aux script, et je ne savais pas jusque-là qu'il était possible d'exclure des chaînes dans des expressions.
 
Mais j'ai à présent découvert les assertions avant, les assertions arrières négatives et le moyen de rendre des expressions non gourmandes. Toutes ces choses là, ... qui ne sont finalement pas supporté par sed  :pfff:  
Alors soit j'essaie de me trouver une autre commande, soit je vais opter pour la solution crade que je voulais éviter:

Code :
  1. if echo "$Chaine" | grep "préfixe"; then
  2.    resultat=`echo "$Chaine" | sed 's/.*\(préfixeMaString.*\)/\1/'`
  3. else
  4.    resultat=`echo "$Chaine" | sed 's/.*\(MaString.*\)/\1/'`
  5. fi

Reply

Marsh Posté le 06-01-2013 à 21:35:49    

salut,
 

Code :
  1. Chaine="sans importance préfixemonMotif et une éventuelle suite
  2. sans importance monMotif et une autre suite"
  3. echo "$Chaine" |sed 's/.*\(\<.*monMotif .*\)/\1/'
  4. préfixemonMotif et une éventuelle suite
  5. monMotif et une autre suite

.* : n'importe quoi
\<.*monMotif : chaîne vide en début de mot + n'importe quoi + monMotif

Reply

Marsh Posté le 07-01-2013 à 07:25:22    

Super, l'expression fonctionne, merci.
 
Sauf que là je récupère n'importe quel bout de mot placé devant MaString.
Or je ne suis intéressé que par les chaînes correspondant exactement à "préfixe".
 
J'ai donc réessayé de remettre "préfixe" entre parenthèse et en le rendant optionnel avec le point d'intérogation:  

Code :
  1. sed 's/.*\(\<\(préfixe\)\?MaString.*\)/\1/'


Mais rien à faire, l'expression match si préfixe est là, mais si il ne l'est pas, l'expression échoue.
 
Remarque, comme je connais mon préfixe, je pourrais aussi tenter une expression avec un: MaString OU préfixeMaString.
J'essaierais ça ce soir.
 
 
Par contre je n'ai pas bien saisi comment, dans '\<.*', le simple fait de lui préciser que c'était en début du mot a finalement débloqué sed. Peux-tu m'explique sa logique?
Ça m'aidera sûrement dans mes prochaines expressions.
 
Merci

Reply

Marsh Posté le 07-01-2013 à 08:24:25    

Code :
  1. Chaine="sans importance préfixemonMotif et une éventuelle suite
  2. sans importance monMotif et une autre suite
  3. sans importance foomonMotif et une autre suite
  4. sans importance sansMotif et une autre suite"
  5. echo "$Chaine" |sed -n 's/.*\(\<\(préfixe\)*monMotif .*\)/\1/p'
  6. préfixemonMotif et une éventuelle suite
  7. monMotif et une autre suite

avec -n et p, pour n'afficher que ce qui correspond au motif.

Reply

Marsh Posté le 07-01-2013 à 22:12:41    

Ah, super, merci beaucoup!
 
D'ailleurs au temps pour moi, avec le point interrogation ça marche aussi. Mais j'ai dû aller un peu vite ce matin, je crois que j'avais un espace entre le préfixe et la string dans l'expression et pas dans la chaine, ou inversement.
 
En fait le '\<' change tout. Je retiendrais.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed