IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

REGEX supprimer un caractère dans une sous chaine


Sujet :

Langage Perl

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 8
    Points : 9
    Points
    9
    Par défaut REGEX supprimer un caractère dans une sous chaine
    Bonjour,
    J'aurai besoin de votre aide, je reprend PERL après un long moment, je souhaiterai supprimer des caractères dans une sous chaine, je suppose que les expressions régulières seraient le moyen le plus efficace de le faire. Je ne sais pas s'il existe une fonction appropriée qui pourrait répondre à mon besoin.
    Voici mon problème:
    j'ai un fichier avec plusieurs lignes de ce type :
    "230000034098|""PT.RLT.1/40T|2/50T|1/100T|2/25""|21530000||||0.00||104808.70|1996|01/01/1998||||||IS01705910||62330||LINR|10|2013|0|-104808.7|T001"
    Le pipe (|) est un séparateur que je ne dois pas supprimer.

    Je souhaiterai supprimer uniquement les pipes (|) qui sont compris entre les doubles guillemets (""), ici en l'occurrence j'aimerai avoir:
    "230000034098|""PT.RLT.1/40T2/50T1/100T2/25""|21530000||||0.00||104808.70|1996|01/01/1998||||||IS01705910||62330||LINR|10|2013|0|-104808.7|T001"
    J'aimerai ensuite supprimer tous les guillemets de ma ligne.
    230000034098|PT.RLT.1/40T2/50T1/100T2/25|21530000||||0.00||104808.70|1996|01/01/1998||||||IS01705910||62330||LINR|10|2013|0|-104808.7|T001
    Est il possible de le faire sans reconstruire un nouveau fichier, juste en parcourant mon fichier déjà ouvert ?

    Pouvez vous m'orienter vers la solution la plus efficace, je n'arrive pas à trouver ce qu'il faudrait faire. En comptant sur votre expérience, merci !

  2. #2
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 256
    Points
    12 256
    Billets dans le blog
    1
    Par défaut
    Je ne comprends pas bien l'histoire des guillemets et du pipe: le premier pipe de ton exemple est entre des guillemets et tu sembles le garder. Peux-tu expliquer?

    Sinon, pour modifier "en place" un fichier, il faut généralement renommer le fichier en entrée et créer un nouveau fichier en sortie ayant le nom du fichier en entrée. Deux autres solutions cependant:
    - lire tout le fichier en mémoire par exemple dans un tableau de lignbes (à condition qu'il ait une taille raisonnable), fermer le fichier en entrée, faire les modifications en mémoire, puis rouvrir le même fichier en mode écriture (ce qui efface le contenu) et écrire ce que tu as en mémoire dans le fichier.
    - si les modifications sont supplément simples, faire un script uniligne avec l'option -i, par exemple, s'il s'agissait uniquement de retirer les guillemets:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    perl -pi.bak -e 's/"//g;' fichier.txt
    qui renomme le fichier d'origine en "fichier.txt.bak" et retire tous les guillemets du fichier fichier.txt (en fait, crée un nouveau fichier fichier.txt sans guillemets).

  3. #3
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Tout d'abord, il n'est pas possible d'écrire en même temps un fichier que l'on lit. Donc il faudra choisir une des solutions suivantes :
    Solution 1
    - renommer le fichier à traiter (définir un nom temporaire avec File::Temp par exemple)
    - ouvrir le fichier renommé en lecture
    - ouvrir le fichier avec le nom d'origine en écriture
    - lire le fichier renommé et écrire le résultat dans le fichier en écriture
    - supprimer le fichier renommé

    Solution 2
    - ouvrir le fichier à traiter en lecture
    - ouvrir un nouveau fichier en écriture (fichier temporaire par exemple avec File::Temp)
    - lire le fichier à traiter et écrire le résultat dans le fichier temporaire
    - fermer les fichiers
    - supprimer le fichier d'origine
    - renommer le nouveau fichier avec le nom d'origine

    Solution 3 (solution que je vais adopter, et qui correspond à la solution 1, intégrée dans les options perl)
    - utiliser les paramètres d'appel perl -pe -i.bak
    - et écrire le traitement de chaque ligne dans le corps du script

    Pour ce qui est de la regexp, il me faut un peu plus de réflexion, je reviens avec la suite plus tard.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  4. #4
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Résultat en uniligne :

    $ echo '230000034098|""PT.RLT.1/40T|2/50T|1/100T|2/25""|21530000||||0.00||104808.70|1996|01/01/1998||||||IS01705910||62330||LINR|10|2013|0|-104808.7|""T001""' | perl -pE 's/("".*?"")/$1 =~ s{\|}{}gr/ge;s/"//g'

    L'expression régulière pour traiter les | entre les doubles "doubles quotes" est là : s/("".*?"")/$1 =~ s{\|}{}gr/ge
    Celle pour enlever les double quotes : s/"//g

    Pour plus d'explications, n'hésite pas à demander.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 8
    Points : 9
    Points
    9
    Par défaut
    Bonjour,

    C'est malheureusement un fichier assez volumineux, je ne peux pas utiliser les tableaux. Je vais procéder en 2 étapes comme vous m'avez conseillé: appliquer la regex sur les doubles guillemets, envoyer le résultat dans un fichier résultat, puis enlever les guillemets sur le fichier résultat.

    Voici mon code:

    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
     
    my $file = "monfichier.txt";
    my $ligne;
     
    open(monfichier,$file) or die("ouverture: $!");
    open(RES,">resultat.txt") or die("ouverture res: $!");
    select(RES);
     
    while( defined( $ligne = <monfichier> ) ) {
    	chomp $ligne;
     	$ligne =~ s/("".*?"")/$1 =~ s{\|}{}gr/ge;
    	print "$ligne\r";
    }
     
    close(monfichier);
    close(RES);
    Voilà où j'en suis actuellement, je ne comprends pas trop la regex, j’essaie toutes les combinaisons possibles mais je n'y arrive pas. l'argument $1 est propre aux commandes je suppose non ?

    Merci de votre aide !

  6. #6
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Les trois solutions que j'ai proposées ne nécessitent pas de charger le fichier totalement en mémoire, elles s'appliquent donc parfaitement aux très gros fichiers.

    Concernant la regexp, qu'est-ce qui ne fonctionne pas ? $1 correspond au motif entre parenthèse, c'est à dire ("".*?"")
    J'expliciterai la regexp cet après-midi (là, je dois partir).

    Pour traiter les ", il suffit de mettre l'instruction $ligne =~ s/"//g après $ligne =~ s/("".*?"")/$1 =~ s{\|}{}gr/ge. Pas la peine de créer un deuxième script et de le lancer dans une 2e passe.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 8
    Points : 9
    Points
    9
    Par défaut
    Ok je vais mettre la suppression des guillemets après la regex compliquée.
    Pour le moment j'ai un problème de syntaxe, voilà l'erreur que j'ai:

    Bareword found where operator expected at corr_scr.pl line 22, near "s{\|}{}gr"

  8. #8
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    OK. Quelle version de perl as-tu ?
    Si tu as une version >= 5.10, ajoute en début de script :

    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 8
    Points : 9
    Points
    9
    Par défaut
    Bonjour, je suis sur windows avec la version 5.8.4 de PERL.

  10. #10
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Dans ce cas, remplace la regexp par celle-ci :
    s/("".*?"")/(my $r=$1) =~ s{\|}{}g;$r/ge
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  11. #11
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 8
    Points : 9
    Points
    9
    Par défaut
    Ca ne plante plus ! Par contre ca n'a pas eu d'effet:

    Voici la ligne dans mon fichier résultat:

    "230000034098|""PT.RLT.1/40T|2/50T|1/100T|2/25""|21530000||0|0|0|0|104808.7|1996|01/01/1998||||||IS01705910||62330||LINR|10|2010|0|-104808.7|T001"
    Mon code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
     
    while( defined( $ligne = <monfichier> ) ) {
    	chomp $ligne;
    	$ligne =~ s/("".*?"")/(my $r=$1)=~s{\|}{}g;$r/ge;
    	print "$ligne\r";
     
    }

  12. #12
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Ça marche chez moi, je l'ai testé, tu as peut-être mal recopier le code ?!

    Je reposte mon test uniligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $ echo '230000034098|""PT.RLT.1/40T|2/50T|1/100T|2/25""|21530000||||0.00||104808.70|1996|01/01/1998||||||IS01705910||62330||LINR|10|2013|0|-104808.7|""T001""' | perl -pe 's/("".*?"")/(my $r=$1) =~ s{\|}{}g;$r/ge;s/"//g'
    230000034098|PT.RLT.1/40T2/50T1/100T2/25|21530000||||0.00||104808.70|1996|01/01/1998||||||IS01705910||62330||LINR|10|2013|0|-104808.7|T001
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 8
    Points : 9
    Points
    9
    Par défaut
    Bonjour,

    J'ai pu résoudre mon problème de cette manière:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    my $st = qq("230000034098|""PT.RLT.1/40T|2/50T|1/100T|2/25""|21530000||||0.00||104808.70|1996|01/01/1998||||||IS01705910||62330||LINR|10|2013|0|-104808.7|T001");
     
    while ($st =~ /(.*"".*?)(\|)(.*?"".*)/)
    {
        $st = $1 . $3;
    }
    print "Résultat :\n" . $st . "\n";
    Merci !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Regex : Recherche chaine de caractère dans une autre chaine de caractère (Unix)
    Par framus.class dans le forum Shell et commandes GNU
    Réponses: 5
    Dernier message: 18/01/2011, 22h05
  2. supprimer certains caractères dans une chaine
    Par rene10 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 31/12/2009, 11h26
  3. supprimer un caractère dans une chaine
    Par agilec dans le forum Débuter
    Réponses: 2
    Dernier message: 29/09/2009, 20h13
  4. Supprimer des caractères dans une chaine
    Par bahamut100 dans le forum Langage
    Réponses: 3
    Dernier message: 12/02/2009, 10h25
  5. [Tableaux] Supprimer des caractères dans une chaine
    Par ddubois dans le forum Langage
    Réponses: 10
    Dernier message: 16/12/2006, 13h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo