OVH Cloud OVH Cloud

[SHELL] remplacer un caractère dans une sous-chaine

16 réponses
Avatar
zelos 414
Bonjour la liste,


Je me heurte depuis quelques temps =E0 un souci de substitution de
caract=E8re dans une sous-chaine.

Voici la cha=EEne d'origine:

type[TEST] date[Sun Dec 16 15:45:53 CET 2007] description[permission
denied] level[critical]

Quelquefois, je la re=E7ois sous cette forme (remarquez qu'un espace
s'est ins=E9r=E9 dans "perm ission" et "cri tical") :

type[TEST] date[Sun Dec 16 15:45:53 CET 2007] description[perm ission
denied] level[cri tical]

J'aimerai donc supprimer tous les espaces ' ' contenus entre crochets
SAUF dans ceux pr=E9c=E9d=E9s de 'date' ou 'creationDate'

Je pense que sed peut suffir mais je n'arrive pas =E0 trouver.

En effet:

echo "description[perm ission denied] " | sed -e 's/\[.*\ .*]/\[\.*_\.*\]/g=
'

et

tr ' ' '_'

ne sont pas corrects.

Auriez-vous une id=E9e?

Merci.

Zelos

6 réponses

1 2
Avatar
Sylvain Sauvage
zelos 414, jeudi 20 décembre 2007, 16:14:31 CET
[…]
Malheureusement, il se peut que
certains [] soient emboîtés aussi dans de rares cas.



Alors ça donne ça :

#! /usr/bin/ruby

while ligne = STDIN.gets
crochet = 0
date = false
until ligne.nil?
case ligne
when /A[dD]ate[/
date = true
print $&
when /A[/
crochet += 1
print $&
when /A]/
if date and crochet.zero?
date = false
else
crochet -= 1
if crochet < 0
# oups, trop de fermants
crochet = 0
end
end
print $&
when /A /
if crochet > 0 and not date
print '_'
else
print ' '
end
when /A./
print $&
end
ligne = $'
end
print "n"
end

--
Sylvain Sauvage
Avatar
Jacques L'helgoualc'h
Sylvain Sauvage a écrit, jeudi 20 décembre 2007, à 16:30 :
[...]
Pour sed, les adresses ne fonctionnent que sur plusieurs
lignes.



Oui,

En revanche, la négation :

> /([^Dd]...|[dD]([^a]..|a([^t].|t[^e])))[/,/]/y/ /_/



On peut tourner la chose autrement : Sed connaît la négation /motif/!,
et on peut emboîter des blocs entre accolades.

Mais ça devient très lourd à gérer avec sed. Il vaudrait
vraiment passer à un vrai langage (Ruby, Perl???).



Sed est Turing-complet, mécréant !

Pour me pardonner d???avoir dit une ânerie :



#!/usr/bin/ruby



Pfff. Sed peut aisément

1/ Isoler les motifs à traiter entre deux lignes debut, fin :

sed -e 's/([a-z]+[[^]]*])/BALISE_debutn1nBALISE_finn/ig'

2/ Traiter uniquement les susdits motifs :

sed -e '/BALISE_debut$/,/^BALISE_fin$/{# Dans le bloc,
/BALISE_/!{# ne pas traiter les bornes,
/^(truc|machin)/!{# ni ces motifs.
s/[[:space:]]/_/g # traitement...
}
}
}'

3/ Recoller les morceaux... (en exercice :)

--
Jacques L'helgoualc'h


--
Lisez la FAQ de la liste avant de poser une question :
http://wiki.debian.net/?DebianFrench
Vous pouvez aussi ajouter le mot ``spam'' dans vos champs "From" et
"Reply-To:"

To UNSUBSCRIBE, email to
with a subject of "unsubscribe". Trouble? Contact
Avatar
zelos 414
Le 20/12/07, Jacques L'helgoualc'h<lhh+ a écrit :
Sylvain Sauvage a écrit, jeudi 20 décembre 2007, à 16:30 :
[...]
> Pour sed, les adresses ne fonctionnent que sur plusieurs
> lignes.

Oui,

> En revanche, la négation :
>
> > /([^Dd]...|[dD]([^a]..|a([^t].|t[^e])))[/,/]/y/ /_/

On peut tourner la chose autrement : Sed connaît la négation /motif /!,
et on peut emboîter des blocs entre accolades.

> Mais ça devient très lourd à gérer avec sed. Il vaudrait
> vraiment passer à un vrai langage (Ruby, Perl???).

Sed est Turing-complet, mécréant !

> Pour me pardonner d???avoir dit une ânerie :

> #!/usr/bin/ruby

Pfff. Sed peut aisément

1/ Isoler les motifs à traiter entre deux lignes debut, fin :

sed -e 's/([a-z]+[[^]]*])/BALISE_debutn1nBALISE_finn/ig'

2/ Traiter uniquement les susdits motifs :

sed -e '/BALISE_debut$/,/^BALISE_fin$/{# Dans le bloc,
/BALISE_/!{# ne pas traiter les bornes,
/^(truc|machin)/!{# ni ces motifs.
s/[[:space:]]/_/g # traitement...
}
}
}'

3/ Recoller les morceaux... (en exercice :)

--
Jacques L'helgoualc'h


--
Lisez la FAQ de la liste avant de poser une question :
http://wiki.debian.net/?DebianFrench
Vous pouvez aussi ajouter le mot ``spam'' dans vos champs "From" et
"Reply-To:"

To UNSUBSCRIBE, email to
with a subject of "unsubscribe". Trouble? Contact .org






Tout d'abord, je remercie tous ceux qui m'ont aidé.
Je ne pouvais pas modifier la source car je n'en ai pas les droits
(systèmes de production). Avec toutes vos indications, je pense
pouvoir réussir mon traitement d'ici la fin de journée.

Merci

Zelos
Avatar
Sylvain Sauvage
Jacques L'helgoualc'h, jeudi 20 décembre 2007, 22:05:14 CET
[…]
> En revanche, la négation :
>
> > /([^Dd]...|[dD]([^a]..|a([^t].|t[^e])))[/,/]/y/ /_/

On peut tourner la chose autrement : Sed connaît la
négation /motif/!,



Ah oui, tiens. On ne lit jamais assez bien les docs.

et on peut emboîter des blocs entre
accolades.

> Mais ça devient très lourd à gérer avec sed. Il v audrait
> vraiment passer à un vrai langage (Ruby, Perl???).

Sed est Turing-complet, mécréant !



Argument facile : c’est une chose d’avoir une machine de
Turing, c’en est une autre d’écrire des programmes uti les avec.

Pour rappel, la démonstration consiste à simuler une machine
à un processeur avec un seul registre et deux instructions.
Ensuite, on utilise le résultat d’autres démonstrations de
simulation : équivalence de cette machine avec une machine à
plusieurs registres, plusieurs rubans… jusqu’à dé montrer qu’on
peut s’en servir pour simuler un langage de haut niveau.
Autant directement utiliser un tel langage.

> Pour me pardonner d???avoir dit une ânerie :

> #!/usr/bin/ruby

Pfff. Sed peut aisément



… mais pas très lisiblement

1/ Isoler les motifs à traiter entre deux lignes debut, fin :

sed -e
's/([a-z]+[[^]]*])/BALISE_debutn1nBALISE_finn/ig'

2/ Traiter uniquement les susdits motifs :

sed -e '/BALISE_debut$/,/^BALISE_fin$/{# Dans le bloc,
/BALISE_/!{# ne pas traiter les bornes,
/^(truc|machin)/!{# ni ces motifs.
s/[[:space:]]/_/g # traitement...
}
}
}'



Gestion des [] imbriqués ? :oP

3/ Recoller les morceaux... (en exercice :)



Ah, ah, la technique habituelle des profs quand ça devient
scabreux : « en exercice », « c’est t rivial »…
Je préfère le « vous verrez ça l’annà ©e prochaine » :o)

--
Sylvain Sauvage
Avatar
Jacques L'helgoualc'h
Sylvain Sauvage a écrit, vendredi 21 décembre 2007, à 10:31 :
Jacques L'helgoualc'h, jeudi 20 décembre 2007, 22:05:14 CET
> [...] Sed connaît la négation /motif/!,

Ah oui, tiens. On ne lit jamais assez bien les docs.



Justement, « info sed » est bien l'une des rares documentations qu'on
peut lire d'un bout à l'autre... Bon, aller fouiner aussi sur
http://sed.sf.net/ peut aider.

> > Mais ça devient très lourd à gérer avec sed. Il vaudrait
> > vraiment passer à un vrai langage (Ruby, Perl???).
>
> Sed est Turing-complet, mécréant !

Argument facile : c???est une chose d???avoir une machine de
Turing, c???en est une autre d???écrire des programmes utiles avec.



Le problème avec Sed, ce n'est pas l'utilité --- plutôt la lisibilité :/

[...]

Gestion des [] imbriqués ? :oP



Si la profondeur reste raisonnable et limitée, c'est possible, mais vite
lourd : la récursivité n'est certes pas un point fort de Sed.

Dans le problème posé, il serait sans doute plus expéditif de corriger
les quelques mots erronés qui peuvent apparaître, s'ils ne sont pas trop
nombreux :

~ $ echo 'Perm ission crit ical perm ission' |
]sed -e 's/(perm)[[:space:]]+ission/1ission/ig
]s/(crit)[[:space:]]+ical/1ical/ig'


Permission critical permission

> 3/ Recoller les morceaux... (en exercice :)

Ah, ah, la technique habituelle des profs quand ça devient
scabreux : « en exercice », « c???est trivial »???



Ici, ça n'a rien de très scabreux.

Je préfère le « vous verrez ça l???année prochaine » :o)



Il y a un précédent bien connu, où la marge n'était pas assez grande :)

Réponse(s) vendredi prochain.
--
Jacques L'helgoualc'h


--
Lisez la FAQ de la liste avant de poser une question :
http://wiki.debian.net/?DebianFrench
Vous pouvez aussi ajouter le mot ``spam'' dans vos champs "From" et
"Reply-To:"

To UNSUBSCRIBE, email to
with a subject of "unsubscribe". Trouble? Contact
Avatar
Jacques L'helgoualc'h
Jacques L'helgoualc'h a écrit, vendredi 21 décembre 2007, à 19:22 :
Sylvain Sauvage a écrit, vendredi 21 décembre 2007, à 10:31 :


[...]
> > 3/ Recoller les morceaux... (en exercice :)
>
> Ah, ah, la technique habituelle des profs quand ça devient
> scabreux : « en exercice », « c???est trivial »???

Ici, ça n'a rien de très scabreux.

> Je préfère le « vous verrez ça l???année prochaine » :o)

Il y a un précédent bien connu, où la marge n'était pas assez grande :)

Réponse(s) vendredi prochain.



Exercice : mettre en majuscules et double espacement le texte entre
crochets précédés de « Cap » ou « Maj ».


Une solution :

sed -re 's/b(Maj|Cap)[([^][]+)]/1BALISE_debutn2nBALISE_finn/g' <texte |
sed -e '/BALISE_debut$/,/^BALISE_fin$/{/BALISE_/!{s/./ u&/g;s/^ //}}' |
sed -ne 'H;${g;s/^n//;s/BALISE_debutn/[/g;s/nBALISE_finn/]/g;p}'

Dans le premier sedscript, on peut remplacer la seconde parenthèse par
« ([^][]*[[^][]*][^][]*|[^][]+) », pour traiter le cas d'un crochet
emboîté de niveau 2 ; le lecteur courageux peut aller plus loin...


Version commentée du troisième :

sed -n -e '
H # stockage de toutes les lignes dans le « hold space »,
${# et à la fin, récupération du hold space
g
# suppression de la ligne 0
s/^n//1
# remplacement global des balises,
s/BALISE_debutn/[/g
s/nBALISE_finn/]/g
# et sortie du résultat
p
}'


Variante avec traitement local pour éviter de stocker tout le fichier
en mémoire, et/ou attendre la fin du pipe :

sed -e '
# Boucle de reconstitution d'une ligne originale
: Ligne
/BALISE_debut$/{
# Boucle interne de lecture de bloc traité
: Bloc
N
/nBALISE_fin$/! b Bloc
# Remplacement des deux balises
s/BALISE_debutn/[/1
N
s/nBALISE_finn/]/1
b Ligne
}'


On peut essayer de regrouper en deux, voire un seul script Sed ---
mais la lisibilité peut en souffrir ().

Bonnes fêtes à tous,
--
Jacques L'helgoualc'h


--
Lisez la FAQ de la liste avant de poser une question :
http://wiki.debian.net/?DebianFrench
Vous pouvez aussi ajouter le mot ``spam'' dans vos champs "From" et
"Reply-To:"

To UNSUBSCRIBE, email to
with a subject of "unsubscribe". Trouble? Contact
1 2