(sed) extraction d'une partie d'un fichier if
Fermé
oqp24
Messages postés
10
Date d'inscription
mercredi 31 mai 2006
Statut
Membre
Dernière intervention
6 juin 2006
-
1 juin 2006 à 14:07
oqp24 Messages postés 10 Date d'inscription mercredi 31 mai 2006 Statut Membre Dernière intervention 6 juin 2006 - 6 juin 2006 à 10:42
oqp24 Messages postés 10 Date d'inscription mercredi 31 mai 2006 Statut Membre Dernière intervention 6 juin 2006 - 6 juin 2006 à 10:42
A voir également:
- (sed) extraction d'une partie d'un fichier if
- Fichier rar - Guide
- Comment réduire la taille d'un fichier - Guide
- Comment ouvrir un fichier epub ? - Guide
- Ouvrir un fichier .bin - Guide
- Comment ouvrir un fichier docx ? - Guide
9 réponses
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
1 juin 2006 à 14:53
1 juin 2006 à 14:53
Salut,
en fait on n'a même pas besoin d'avoir des paragrphes tant qu'on est sur de ça
commence par DDD et finissent par FFF.
- je récupère le contenu de fichier dans une variable scalaire (mode slurp)
- je fais une recherche progressive de DDD et j'affiche le contenu de la chaine jusqu'à FFF uniquement si quelque part j'ai XXX entre DDD et FFF)
pour ça j'utilise le modificateur g et l'assertion \G
Si je me rappelle bien Dal a des bonnes connaissances en Perl donc il peut corriger mon script. Je suis sous Win maintenant et je ne peux pas tester.
Pour execution
perl /rep/scripts/extrat.pl nom_fichier
lami20j
en fait on n'a même pas besoin d'avoir des paragrphes tant qu'on est sur de ça
commence par DDD et finissent par FFF.
#! /usr/bin/perl use warnings;use strict; undef $/; my $fic = <>; pos($fic)=0; while ( $fic =~ /DDD/g ){ if ($fic =~ /\G(.*XXX.*FFF)/){ print $1; } }Je ne l'ai pas testé mais l'algo est suivant :
- je récupère le contenu de fichier dans une variable scalaire (mode slurp)
- je fais une recherche progressive de DDD et j'affiche le contenu de la chaine jusqu'à FFF uniquement si quelque part j'ai XXX entre DDD et FFF)
pour ça j'utilise le modificateur g et l'assertion \G
Si je me rappelle bien Dal a des bonnes connaissances en Perl donc il peut corriger mon script. Je suis sous Win maintenant et je ne peux pas tester.
Pour execution
perl /rep/scripts/extrat.pl nom_fichier
lami20j
asevere
Messages postés
13087
Date d'inscription
lundi 28 janvier 2002
Statut
Webmaster
Dernière intervention
23 novembre 2024
426
1 juin 2006 à 20:14
1 juin 2006 à 20:14
Bonsoir,
Une astuce pour ne pas trop te pourrir la vie :)
Avec sed seulement, on oublie (travail ligne/ligne, donc pas top)
Avec awk seulement, ça doit être fesable, mais imbittable
Avec les deux ensemble par contre :)
awk travaillant sur des enregistrements et non sur des lignes ( le separateur d'enregistrement est \n par defaut) ça doit être réalisable....
Voyons un peu...
La premiere chose a faire est d'avoir un separateur de champ...
On obtient quelque chose du genre:
IE:
Maintenant, qu'on a ces champ, il suffit de passer ça a awk, en lui demendant d'afficher les enregistrement qui nous sont utiles...
Quelques infos:
Pour ecraser le separateur de champ par defaut, il faut renseigner la variable RS dans un bloque BEGIN tant qu'a faire pour ne le faire qu'une fois au début du traitement
Pour info:
L'expression !/DDD.*XXX.*FFF.*/ ne suffit pas, elle retourne aussi les enregistrement vide (dus aux RECORD_SEP RECORD_SEP généré par sed plus haut)
Donc:
(PS: je sais, c'est optimisable)
Une astuce pour ne pas trop te pourrir la vie :)
Avec sed seulement, on oublie (travail ligne/ligne, donc pas top)
Avec awk seulement, ça doit être fesable, mais imbittable
Avec les deux ensemble par contre :)
awk travaillant sur des enregistrements et non sur des lignes ( le separateur d'enregistrement est \n par defaut) ça doit être réalisable....
Voyons un peu...
La premiere chose a faire est d'avoir un separateur de champ...
sed -e 's/\(^DDD.*\)/RECORD_SEP\1/' -e 's/\(^FFF.*\)/\1RECORD_SEP/' fichierLà on ajoute RECORD_SEP avant les lignes commencant par DDD et aprés les lignes commencant par FFF.
On obtient quelque chose du genre:
RECORD_SEPDDDblablabla blablablalll blablablammmmmmmm FFF blablablassRECORD_SEP RECORD_SEPDDD blablabla blablablaoo lsdqkgsqdXXX blablabla FFF blablabladdRECORD_SEP RECORD_SEPDDD blablablaqq blablablasd FFF blablabla RECORD_SEPSoit 6 enregistrements (C'est la faiblesse), en affinant, on doit pouvoir recuperer 3 enregistrements
IE:
DDDblablabla blablablalll blablablammmmmmmm FFF blablablass RECORD_SEPDDD blablabla blablablaoo lsdqkgsqdXXX blablabla FFF blablabladd RECORD_SEPDDD blablablaqq blablablasd FFF blablablaMais c'est pas grave :)
Maintenant, qu'on a ces champ, il suffit de passer ça a awk, en lui demendant d'afficher les enregistrement qui nous sont utiles...
Quelques infos:
Pour ecraser le separateur de champ par defaut, il faut renseigner la variable RS dans un bloque BEGIN tant qu'a faire pour ne le faire qu'une fois au début du traitement
BEGIN{ RS="RECORD_SEP" }la syntaxe pour afficher un enregistrement s'il correspond a une reg_exp est:
/reg_exp/{ print $0} ($0 représente l'enregistrement courant)L'inverse:
!/reg_exp/{ print $0}Ce qui nous donne:
awk 'BEGIN{ RS="RECORD_SEP" } /DDD.*XXX.*FFF.*/ { print $0 }'pour matcher un paragraphe avec XXX et
awk 'BEGIN{ RS="RECORD_SEP" } !/DDD.*XXX.*FFF.*/ && /DDD.*FFF.*/ { print $0 }'pour matcher un paragraphe sans XXX
Pour info:
L'expression !/DDD.*XXX.*FFF.*/ ne suffit pas, elle retourne aussi les enregistrement vide (dus aux RECORD_SEP RECORD_SEP généré par sed plus haut)
Donc:
$ sed -e's/\(^DDD.*\)/RECORD_SEP\1/' -e 's/\(^FFF.*\)/\1RECORD_SEP/' test |awk 'BEGIN{ RS="RECORD_SEP" } /DDD.*XXX.*FFF.*/ { print $0 }' DDD blablabla blablablaoo lsdqkgsqdXXX blablabla FFF blablabladd $ sed -e's/\(^DDD.*\)/RECORD_SEP\1/' -e 's/\(^FFF.*\)/\1RECORD_SEP/' test |awk 'BEGIN{ RS="RECORD_SEP" } !/DDD.*XXX.*FFF.*/ && /DDD.*FFF.*/ { print $0 }' DDDblablabla blablablalll blablablammmmmmmm FFF blablablass DDD blablablaqq blablablasd FFF blablablaCa doit repondre à ton attente :)
(PS: je sais, c'est optimisable)
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
1 juin 2006 à 20:19
1 juin 2006 à 20:19
Salut,
ça fait un bail. Commen tu vas?
Je crois que jipicy n'aura plus des maux de têtes.
Je suis trop paresseux pour faire un truc pareil. Félicitations!
lami20j
ça fait un bail. Commen tu vas?
Je crois que jipicy n'aura plus des maux de têtes.
Je suis trop paresseux pour faire un truc pareil. Félicitations!
lami20j
asevere
Messages postés
13087
Date d'inscription
lundi 28 janvier 2002
Statut
Webmaster
Dernière intervention
23 novembre 2024
426
>
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
1 juin 2006 à 21:27
1 juin 2006 à 21:27
Ava bien,
Beaucoup de boulot, alors je post moins :)
Beaucoup de boulot, alors je post moins :)
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
1 juin 2006 à 14:19
1 juin 2006 à 14:19
Salut,
Je ne vois pas très bien où tu places tes "paragraphes" 1, 2 et 3 dans ton exemple ci-dessus.
Si ce que tu veux afficher ce sont des lignes (c'est à dire une suite de caractères avec CR au bout), tu peux utiliser grep, et l'option -v ou --invert-match pour les lignes ne contenant pas l'objet de la recherche (du moins dans le GNU grep).
Dal
Je ne vois pas très bien où tu places tes "paragraphes" 1, 2 et 3 dans ton exemple ci-dessus.
Si ce que tu veux afficher ce sont des lignes (c'est à dire une suite de caractères avec CR au bout), tu peux utiliser grep, et l'option -v ou --invert-match pour les lignes ne contenant pas l'objet de la recherche (du moins dans le GNU grep).
Dal
oqp24
Messages postés
10
Date d'inscription
mercredi 31 mai 2006
Statut
Membre
Dernière intervention
6 juin 2006
1 juin 2006 à 14:45
1 juin 2006 à 14:45
Non ce serai trop simple.
Comment extraire les paragraphes contenant
la chaine XXX .(Parag 2)
on doit obtenir:
DDD blablabla
blablablaoo
lsdqkgsqdXXX blablabla
FFF blablabladd
Comment extraire les paragraphes ne contenant pas
la chaine XXX. (Parag 1 et 3)
on doit obtenir:
DDDblablabla
blablablalll
blablablammmmmmmm
FFF blablablass
DDD blablablaqq
blablablasd
FFF blablabla
Comment extraire les paragraphes contenant
la chaine XXX .(Parag 2)
on doit obtenir:
DDD blablabla
blablablaoo
lsdqkgsqdXXX blablabla
FFF blablabladd
Comment extraire les paragraphes ne contenant pas
la chaine XXX. (Parag 1 et 3)
on doit obtenir:
DDDblablabla
blablablalll
blablablammmmmmmm
FFF blablablass
DDD blablablaqq
blablablasd
FFF blablabla
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
1 juin 2006 à 15:09
1 juin 2006 à 15:09
Encore une chose si jamais tu essaies le script.
Il faut inverser le sens puisque tu as besoin de Comment extraire les paragraphes ne contenant pas
Donc au lieu de
$fic =~ /\G(.*XXX.*FFF)/
écrit
$fic !~ /\G(.*XXX.*FFF)/
lami20j
Il faut inverser le sens puisque tu as besoin de Comment extraire les paragraphes ne contenant pas
Donc au lieu de
$fic =~ /\G(.*XXX.*FFF)/
écrit
$fic !~ /\G(.*XXX.*FFF)/
lami20j
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
oqp24
Messages postés
10
Date d'inscription
mercredi 31 mai 2006
Statut
Membre
Dernière intervention
6 juin 2006
1 juin 2006 à 15:16
1 juin 2006 à 15:16
Argh stop pitié pas de PERL
Vos solution sont surement bonne mais hélas ne me servent pas.
Vos solution sont surement bonne mais hélas ne me servent pas.
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
1 juin 2006 à 15:36
1 juin 2006 à 15:36
stop pitié pas de PERL ok, je ne dit plus rien.
lami20j
lami20j
oqp24
Messages postés
10
Date d'inscription
mercredi 31 mai 2006
Statut
Membre
Dernière intervention
6 juin 2006
>
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
1 juin 2006 à 15:45
1 juin 2006 à 15:45
Merci quand meme
Have a good time
Have a good time
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
1 juin 2006 à 17:44
1 juin 2006 à 17:44
Re,
C'est dommage de ne pas utiliser Perl, car c'est un outil très puissant pour la manipulation de texte.
Je comprend mieux ton concept de "paragraphe".
Je ne connais pas bien awk, mais s'agissant de sed, à ma connaissance celui-ci travaille sur des lignes. Là tes "paragraphes" sont composés d'un nombre indéterminé de lignes avec des délimiteurs situés sur des lignes différentes.
Tu peux cependant faire un script shell qui met dans une variable les "paragraphes" en question en fonction des délimiteurs et qui contrôle pour chaque ligne faisant partie du paragraphe si ton marqueur "XXX" y figure.
Tu fais une boucle (par exemple en bash ou sh) :
while read ligne
do
(...)
done <les_datas.txt
et dedans tu mets tes tests sed sur chaque $ligne, la variable de stockage des paragraphes (initialisée si c'est un marqueur de début, mise à jour sinon), un drapeau si le marqueur "XXX" est présent, un test d'affichage du contenu de la variable de stockage du paragraphe courant en fonction du drapeau (si le marqueur de fin de paragraphe est atteint), etc.
Je n'ai pas le temps de te faire le script tout cuit, mais c'est comme çà que je ferai.
Dal
C'est dommage de ne pas utiliser Perl, car c'est un outil très puissant pour la manipulation de texte.
Je comprend mieux ton concept de "paragraphe".
Je ne connais pas bien awk, mais s'agissant de sed, à ma connaissance celui-ci travaille sur des lignes. Là tes "paragraphes" sont composés d'un nombre indéterminé de lignes avec des délimiteurs situés sur des lignes différentes.
Tu peux cependant faire un script shell qui met dans une variable les "paragraphes" en question en fonction des délimiteurs et qui contrôle pour chaque ligne faisant partie du paragraphe si ton marqueur "XXX" y figure.
Tu fais une boucle (par exemple en bash ou sh) :
while read ligne
do
(...)
done <les_datas.txt
et dedans tu mets tes tests sed sur chaque $ligne, la variable de stockage des paragraphes (initialisée si c'est un marqueur de début, mise à jour sinon), un drapeau si le marqueur "XXX" est présent, un test d'affichage du contenu de la variable de stockage du paragraphe courant en fonction du drapeau (si le marqueur de fin de paragraphe est atteint), etc.
Je n'ai pas le temps de te faire le script tout cuit, mais c'est comme çà que je ferai.
Dal
oqp24
Messages postés
10
Date d'inscription
mercredi 31 mai 2006
Statut
Membre
Dernière intervention
6 juin 2006
1 juin 2006 à 17:56
1 juin 2006 à 17:56
N'ayant pas le choix, j'ai deja commencé un truc dans ce genre.
Dommage de ne pas avoir la commande toute simple qui tue, car les fichiers à traiter sont énormes.
Merci tout de même.. En esperant qu'un petit genie...
Dommage de ne pas avoir la commande toute simple qui tue, car les fichiers à traiter sont énormes.
Merci tout de même.. En esperant qu'un petit genie...
jipicy
Messages postés
40842
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 897
1 juin 2006 à 21:29
1 juin 2006 à 21:29
Salut Adrien,
Chapeau bas Mister Severe ;-))
Effectivement comme l'a dit lami20j, tu m'ôtes des maux de la boîte cranienne ;-))
Bon en attendant en essayant d'optimiser (un tant soit peu) je suis arrivé à ça :
Chapeau bas Mister Severe ;-))
Effectivement comme l'a dit lami20j, tu m'ôtes des maux de la boîte cranienne ;-))
Bon en attendant en essayant d'optimiser (un tant soit peu) je suis arrivé à ça :
sed 's/\(DDD\)/==\1/' fich.txt | awk 'BEGIN { RS="==" } !/XXX/ { print $0 }' DDDblablabla blablablalll blablablammmmmmmm FFF blablablass DDD blablablaqq blablablasd FFF blablabla $ sed 's/\(DDD\)/==\1/' fich.txt | awk 'BEGIN { RS="==" } /XXX/ { print $0 }' DDD blablabla blablablaoo lsdqkgsqdXXX blablabla FFF blablabladdMerci Adrien.
[Dal]
Messages postés
6203
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
29 janvier 2025
1 099
2 juin 2006 à 10:19
2 juin 2006 à 10:19
Bravo !
Content de te revoir sur le forum :)
En fait, on peut même se passer de sed, puisque "DDD" est déjà un délimiteur :) .. on pourrai simplement le remettre dans l'instruction print.
Enfin, pour que celà marche (cette syntaxe, comme celle de jipicy), il faut que les délimiteurs DDD et FFF ne risquent pas de se retrouver ailleurs dans le corps du paragraphe et que l'on n'ait donc pas à vérifier qu'ils soient en début de ligne.
Dal
Content de te revoir sur le forum :)
En fait, on peut même se passer de sed, puisque "DDD" est déjà un délimiteur :) .. on pourrai simplement le remettre dans l'instruction print.
$ awk 'BEGIN { RS="DDD" } /XXX/ { print "DDD"$0 }' < fich.txt DDD blablabla blablablaoo lsdqkgsqdXXX blablabla FFF blablabladd $ awk 'BEGIN { RS="DDD" } \!/XXX/ && /.*FFF.*/ { print "DDD"$0 }' < testsed.txt DDDblablabla blablablalll blablablammmmmmmm FFF blablablass DDD blablablaqq blablablasd FFF blablabla
Enfin, pour que celà marche (cette syntaxe, comme celle de jipicy), il faut que les délimiteurs DDD et FFF ne risquent pas de se retrouver ailleurs dans le corps du paragraphe et que l'on n'ait donc pas à vérifier qu'ils soient en début de ligne.
Dal
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
2 juin 2006 à 11:18
2 juin 2006 à 11:18
Salut,
on peut même se passer de sed, puisque "DDD" est déjà un délimiteur
C'est exactement à ça que j'ai pensé, mais t'es plus rapide que moi.
Awk je ne connais pas du tout, donc hier soir après la solution d'asevere j'ai commencé à lire un peu awk et ce matin en train d'aller au boulot j'ai pense "mais pourquoi on crée un delimiteur s'il existe déjà". Mais comme tu le dit, ça ne marche que si les délimiteurs DDD et FFF
De toute façon parser du texte ça veut dire parser de texte. Maintenant il faut voir les capacités des outils qu'on utilise.
Et Perl n'est qu'un fils de sed et awk, qui c'est vrai a bien agrandi depuis....
lami20j
on peut même se passer de sed, puisque "DDD" est déjà un délimiteur
C'est exactement à ça que j'ai pensé, mais t'es plus rapide que moi.
Awk je ne connais pas du tout, donc hier soir après la solution d'asevere j'ai commencé à lire un peu awk et ce matin en train d'aller au boulot j'ai pense "mais pourquoi on crée un delimiteur s'il existe déjà". Mais comme tu le dit, ça ne marche que si les délimiteurs DDD et FFF
De toute façon parser du texte ça veut dire parser de texte. Maintenant il faut voir les capacités des outils qu'on utilise.
Et Perl n'est qu'un fils de sed et awk, qui c'est vrai a bien agrandi depuis....
lami20j
oqp24
Messages postés
10
Date d'inscription
mercredi 31 mai 2006
Statut
Membre
Dernière intervention
6 juin 2006
6 juin 2006 à 10:42
6 juin 2006 à 10:42
Bravo Severe et merci pour ton aide ca marche nickel.
Merci aussi aux autres mais helas comme l'a si bien dit DAL, les delimitteurs, pour mon cas peuvent se retrouver n'importe ou dans le fichier.
A+
Merci aussi aux autres mais helas comme l'a si bien dit DAL, les delimitteurs, pour mon cas peuvent se retrouver n'importe ou dans le fichier.
A+
1 juin 2006 à 15:05
Je suis sur une tres grosse prod et il y a donc bcp de restriction.
Dommage
1 juin 2006 à 15:07
d'accord mais Perl est integré dans les système Unix donc normalement tu ne dois pas avoir des problèmes.
En fait les seul problèmes que tu peux avoir c'est la version de Perl, puisque les regex de Perl on bien evoulées.
lami20j
1 juin 2006 à 15:13