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 :

Récupérer motif entre des guillemets


Sujet :

Langage Perl

  1. #1
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut Récupérer motif entre des guillemets
    Bonjour,

    Je parcours un fichier et dois récupérer tous ce qu'il y a d'écrit entre guillemets.
    Et enregistrer chaque valeurs récupérées dans un tableau.

    Voici un exemple de texte en entrée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    	Mazotu: 4.15"
    	Vivou: 1.885"
    		"Première chaine à récupérer" External References? No
    		Reject "Deuxième chaine à récupérer" Instances? Yes
    		Enable Runtime "Troisième
    		chaine à récupérer qui est sur 2 ligne"? No
    		Use Release 4.0 Scope Rules? No
    				Font Name: "Quatrième chaine à récupérer" gfgfg || "Cinquième chaine à récupérer"
    				Font Name: "Sixième chaine à récupérer" gfgfg || "Septième chaine
    				à récupérer sur deux lignes"
    Mon code doit me donner en sortie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Tab[0]		Première chaine à récupérer
    Tab[1]		Deuxième chaine à récupérer
    Tab[2] 		Troisième chaine à récupérer qui est sur 2 ligne
    Tab[3]		Quatrième chaine à récupérer
    Tab[4]		Cinquième chaine à récupérer
    Tab[5]		Sixième chaine à récupérer 
    Tab[6]		Septième chaine à récupérer sur deux lignes
    J'ai essayé de faire avec une cherche par bloc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my $in_bloc = ($ligne =~ m/\"/) .. ($ligne =~ m{\w+\"});
    Mais ça marche mal car il y a des guillemets partout...

    Quelqu'un serait me venir en aide svp ?

  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
    Billets dans le blog
    1
    Par défaut
    Tu peux continuer dans la même voie que celle que je t'ai indiquée sur l'autre post:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    print "$1\n" if $line =~ /"([^"]+)"/; # récupère 4ème chaine
    print "$2\n" if $line =~ /"([^"]+)"[^"]*"([^"]+)"/; # récupère 5ème chaine
    print "$3\n" if ...
    Mais ça va vite devenir ingérable.

    De plus, comme je te l'ai déjà dit, les chaines multilignes posent vraiment un problème, d'autant plus que l'on a du mal à les identifier et à les distinguer d'autres bizarretés dans ton fichier:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Mazotu: 4.15"
    Vivou: 1.885"
    Peut être considéré comme une chaîne multiligne. Comment les reconnaître?

  3. #3
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut
    Merci de t'intéresser à mon problème

    C'est tout simple,

    Une chaine multiligne ou simple par commence par une guillemet double et fini par une guillemet double.

    Pour :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Mazotu: 4.15"
    Vivou: 1.885"
    Ne pas traiter c'était un cas d'exception que je gérerai autrement.

    Donc quand sur ma ligne j'ai une guillemet je recupère tout ce qu'il y a jusqu’à la guillemet d'après.
    Sur une simple ligne ou multiligne il peut y en avoir plusieurs exemple : "Cinquième chaine à récupérer" ou la "Septième chaine à récupérer sur deux lignes"

    Est ce plus clair ?

  4. #4
    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
    Billets dans le blog
    1
    Par défaut
    On peut essayer une reconnaissance progressive avec fusion de la ligne avec la ligne suivante quand on se retrouve avec un seul guillemet et appel récursif.

    Un truc dans ce goût-là (code fait à la va-vite et pas du tout testé):

    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
    17
    18
    while (<in>) {
        chomp;
    	next if /"$/;  #elimine les premières lignes se terminant par "
    	next unless /"/;  #elimine les lignes sans guillemets
    	parcourt_ligne ($_);
    }
     
    sub parcourt_ligne {
    	my $ligne = shift;
    	while ( $ligne =~ /"([^"]+)"/ ) {
    	 	print "$1\n";
    	 	$ligne =~ s/[^"]+"([^"]+)"//; # supprime le debut de la ligne jusqu'à ce qui a déjà été reconnu
    	 }
    	 if ($ligne =~ /=/) { #guillemet orphelin, donc chaine multiligne
    	 	$ligne = $ligne . <in>; #recuperation ligne suivante
    	 	parcourt_ligne ($ligne);
    	 }
    }

    Il y a certainement un bug ici ou là, mais ça devrait à peu près marcher.

  5. #5
    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
    Billets dans le blog
    1
    Par défaut
    Bonjour, une version corrigée et testée rapidement:

    Données:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    		"Premiere chaine a recuperer" External References? No
    		Reject "Deuxieme chaine a recuperer" Instances? Yes
    		Enable Runtime "Troisieme
    		chaine a recuperer qui est sur 2 ligne"? No
    		Use Release 4.0 Scope Rules? No
    				Font Name: "Quatrieme chaine a recuperer" gfgfg || "Cinquieme chaine a recuperer"
    				Font Name: "Sixieme chaine a recuperer" gfgfg || "Septieme chaine
    				a recuperer sur deux lignes"

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    use strict;
    use warnings;
     
    my $file_in = "input.txt";
    open FILE_IN, "<$file_in" or die "cannot open $file_in $!";
     
    while (<FILE_IN>) {
    	chomp;
    	s/\r//; # enlève retours chariot Windows 
    	# next if /"$/;  cette instruction doit être enlévée, sinon on perd 4 et 5 eme chaines
    	next unless /"/;  #elimine les lignes sans guillemets
    	parcourt_ligne ($_);
    }
     
    sub parcourt_ligne {
    	my $ligne = shift;
    	while ( $ligne =~ /"([^"]+)"/ ) {
    	 	print "$1\n";
    	 	$ligne =~ s/[^"]+"([^"]+)"//; # supprime le debut de la ligne jusqu'à ce qui a déjà été reconnu
    	 }
    	 if ($ligne =~ /"/) { #guillemet orphelin, donc chaine multiligne
    	 	my $new_line = <FILE_IN>;
    	 	chomp $new_line;
    	 	$new_line =~ s/\s+/ /;
    	 	my $line = $ligne . $new_line; #recuperation ligne suivante
    	 	parcourt_ligne ($line);
    	 }
    }
    Et le résultat:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $ perl guillemets.pl
    Premiere chaine a recuperer
    Deuxieme chaine a recuperer
    Troisieme chaine a recuperer qui est sur 2 ligne
    Quatrieme chaine a recuperer
    Cinquieme chaine a recuperer
    Sixieme chaine a recuperer
    Septieme chaine a recuperer sur deux lignes

  6. #6
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut
    Bonjour,

    Merci énormément Lolo 78.
    Puis je te demander une dernière petite aide.

    1) Je ne comprend pas tout dans ton code.
    J'aimerai vraiment le comprendre parfaitement afin de pouvoir le faire évoluer et m'en servir correctement.

    Peux tu me commenter de façon très détaillé ce que tu as fais pas à pas s'il te plait.

    Par exemple :

    /"([^"]+)"/ : j'ai un peu du mal a tout comprendre ce que fait cette reg exp.
    pourquoi un chomp ligne 8 ? enleve le retour chariot qui est eventuellement à la fin de la chaine ?
    l'appel de la fonction avec le $_ fait quoi exactement ?
    my $ligne = shift ça veut dire ? retourne la première valeur d'un array ?
    etc...

    2) Aussi, imagine que mon fichier que je dois traiter en entrée fait 500 000 lignes, est ce que ce code sera fonctionnel ?

    3) J'ai vu que ça fonctionne si mon couple de guillemets est sur plus de 2 lignes, par exemple 3,4,5 lignes. C'est grâce à l'appel recursif ?
    Idem si j'ai 2,3,4,5, etc.. couples de guillemets sur la même ligne ?

    J'espère ne pas trop abusé de ta gentillesse.

    Merci énormément encore du temps que tu m'as consacré.

    et bonne journée

  7. #7
    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
    Billets dans le blog
    1
    Par défaut
    [^"] est une classe de caractère qui reconnaît tout sauf un guillement (le ^ en début d'une classe de caractère est la négation de tout ce qu'il y a dans la classe).
    Donc, /"([^"]+)"/ reconnaît un guillemet, suivi de 1 ou plusieurs caractères autres que des guillemets (autant que possible) suivi d'un autre guillemet. Et les parenthèses permettet de capturer ce qu'il y a entre les guillemets.

    Le chomp enlève les sauts de ligne. J'ai dû ajouter "s/\r//;" pour enlever le caractère \r (retour chariot) parce que j'ai testé sous Unix alors que tes données ont été récupérées sous Windows.

    récupère le premier élément du tableau par défaut @_, qui contient les paramètres passés à la fonction. C'est équivalent à:

    Le code lit les lignes au fur et à mesure, donc il devrait fonctionner sans problème même si le fichier est très gros. Mais si tu stockes les chaînes résultat dans un tableau comme tu semblais le faire d'après ton autre post (au lieu de seulement les afficher à l'écran comme je l'ai fait), alors il faut vérifier que ton tableau ne va pas saturer la mémoire de l'ordinateur.

    L'appel récursif permet effectivement de gérer plus facilement les multilignes s'étendant sur plus de seulement 2 lignes, et aussi les cas du genre une ligne comportant une (ou plusieurs) chaîne(s) + le début d'une chaîne multiligne, ou inversement une ligne avec la fin d'une chaîne multiligne et une ou plusieurs chaines, etc., bien que je n'aie pas testé les cas les plus tordus.

    permet d'enlever les espaces gênants en début de ligne pour les chaînes multilignes.

    N'hésite pas à demander si d'autre parties du code te paraissent obscures.

  8. #8
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut
    Bonjour,

    Merci beaucoup pour ton explication précise.

    Si j'ai bien tout compris, j'ai traduit ton code en un espèce d'algo afin de tout comprendre :

    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
    17
    18
    19
    20
    21
    22
    23
    lecture fichier{
    	suppression retour chariot
    	elimination ligne qui ne comporte pas de guillemets
    	parcours_ligne ($_)
    }
     
    fonction parcours_ligne{
    	ma ligne = premier élément du tableau @_ qui contient les param passés à la fonction
     
    	Tant que ma ligne = reconnait une guillemet, suivi de 1 ou plusieurs caractère autres que des guillemets (autant que possible)
    	suivi d'une autre guillemet{
     
    		print $1 => notre caputure via les parenthèses de la reg exp
    		ma ligne = Suppression du debut de la ligne jusqu'a ce qui a déja été reconnu
    	}
     
    	si ma ligne = cas de guillmet orphelin, donc chaine multiple{
    		ma nouvelle ligne = mon fichier
    		elimination ligne ne comporte pas de guillemets
    		ma liNe = ma ligne et ma nouvelle ligne
    		parcours_ligne ($liNe)
    	}
    }
    Est ce bien cela ?

    Encore merci pour ton aide

  9. #9
    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
    Billets dans le blog
    1
    Par défaut
    Oui, tu as bien compris, sauf pour la ligne en rouge ci-dessous.

    Citation Envoyé par oliviernouhi Voir le message
    ma nouvelle ligne = mon fichier
    elimination ligne ne comporte pas de guillemets
    ma liNe = ma ligne et ma nouvelle ligne
    parcours_ligne ($liNe)
    En fait, je ne veux pas éliminer une ligne ne comportant pas de guillemet car je suis ici au milieu d'un multiligne (sinon celui-ci serait amputé de sa partie centrale).

    La ligne:

    permet d'éliminer les espaces superflus en début de ligne quand je parse par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    		Enable Runtime "Troisieme
    		chaine a recuperer qui est sur 2 ligne"? No
    pour éviter de se retrouver avec une chaîne ressemblant à ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Troisieme		chaine a recuperer qui est sur 2 ligne
    Donc ce code remplace tous les espaces entre "troisième" et "chaîne" par un seul espace, pour obtenir:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Troisieme chaine a recuperer qui est sur 2 ligne
    ce qui est plus propre et plus lisible.

  10. #10
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut
    Tout est claire merci bien.

    Dernière petite question.

    Si jamais j'ai une ligne qui comporter guillemet guillmet sans rien entre ça bug, c'est normal ?

    par exemple en fichier d'entrée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    				String: E512="La colonne défaut doit être utilisée."
    				String: E513="Vous n'avez pas les habilitations pour modifier un filtre public."
    				String: S101 	= ""
    				String: ENT_Adresse		= "Adresse"
    				String: ENT_AdresseGeo		= "Adresse geographique"
    J'ai cetter erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 61, <FILE_IN> line 5.
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 59, <FILE_IN> line 5.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 60, <FILE_IN> line 5.
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 61, <FILE_IN> line 5.
    Tu vois comment gérer ça ?

    voici mon code actuel qui a un peu évolué :

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    use strict;
    use warnings;
     
    my @tab =([0]);
    my $cpt = 0;
    my $i = 0;
     
    $tab[0][0]="ID";
    $tab[0][1]="Ligne";
    $tab[0][2]="Data"; 
     
    my $file_in = "X7_sans_com_sans_desc.apt";
    open FILE_IN, "<$file_in" or die "cannot open $file_in $!";
    open ECRIRE,  '>', "parserExtracteur.txt" or die("Erreur de création de parserExtracteur.txt");
     
    #####################################################################################################################################################################
    #                                                                                                                                                                   #
    # Technique de recherche : reconnaissance progressive avec fusion de la ligne avec la ligne suivante quand on se retrouve avec un seul guillemet et appel récursif  #
    #                                                                                                                                                                   #
    #####################################################################################################################################################################
     
    while (<FILE_IN>) { # Lecture des lignes au fur est à mesure
    	$cpt++;
    	chomp; # Enlève le retour chariot qui pourrait être eventuellement à la fin de la chaine
    	s/\r//; # Enlève retours chariot Windows (compatibilité unix)
    	next unless /"/;  # Elimine les lignes qui ne comporte pas de guillemets
    	parcourt_ligne ($_);
    }
     
    sub parcourt_ligne {
    	# L'appel récursif permet de gérer plus facilement les multilignes s'étendant sur plus de seulement 2 lignes, et aussi les cas du genre une
    	# ligne comportant une (ou plusieurs) chaîne(s) + le début d'une chaîne multiligne, ou inversement une ligne avec la fin d'une chaîne multiligne et une ou plusieurs 
    	# chaines,etc...
     
    	my $ligne = shift; 
    	# Récupère le premier élément du tableau par défaut @_, qui contient les paramètres passés à la fonction equivalent à shift @_
     
    	if (($ligne =~ /^\t*Left:/) || ($ligne =~ /^\t*Top:/) || ($ligne =~ /^\t*Width:/) || ($ligne =~ /^\t*Height:/)){
    		# ne rien faire
    		print "toto\n";
    	}
    	else{
    		while ( $ligne =~ /"([^"]+)"/ ) { 
    		# [^"] est une classe de caractère qui reconnaît tout sauf un guillement (le ^ en début d'une classe de caractère est la négation de tout ce qu'il y a dans la classe).
    		# Donc, /"([^"]+)"/ reconnaît un guillemet, suivi de 1 ou plusieurs caractères autres que des guillemets (autant que possible) suivi d'un autre guillemet. Et
    		# les parenthèses permettent de capturer ce qu'il y a entre les guillemets.
     
    			# print "$1\n";
    			print ECRIRE $tab[$i][0] = $i;
    			print ECRIRE $tab[$i][1] = " : ";
    			print ECRIRE $tab[$i][2] = $1;
    			print ECRIRE "\n\n";
    			$i++;
     
    			$ligne =~ s/[^"]+"([^"]+)"//; # Supprime le debut de la ligne jusqu'à ce qui a déjà été reconnu
    		 }
    		 if ($ligne =~ /"/) { # Cas de guillemet orphelin, donc chaine multiligne
    			my $new_line = <FILE_IN>;
    			chomp $new_line;
    			$new_line =~ s/\s+/ /; # Permet de supprimer les espaces gênants en début de ligne pour les chaînes multilignes.
    			my $line = $ligne . $new_line; # On recupère la ligne suivante
    			parcourt_ligne ($line);
    		 }
    	}
    }
     
    close ECRIRE;
    close FILE_IN;
    Y aurait il un moyen d'exclure tous les cas de "" => 2 guillemets collés

    Merci d'avance

  11. #11
    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
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    je pense que l'on peut modifier le while dans la fonction parcourt_ligne.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    while ( $ligne =~ /"([^"]*)"/ ) { 
    # Donc, /"([^"]*)"/ reconnaît un guillemet, suivi de 0 ou plusieurs caractères autres que des guillemets (autant que possible) suivi d'un autre guillemet. Et
    De cette façon les chaînes "" seront traitées par le while (0 ou plusieurs caractères autre que des guillemets, au lieu de 1 ou plusieurs caractères autres que des guillemets, ce qui est plus logique puisque ce n'est pas un multiligne, alors que ce que tu as est dû au fait que "" n'était pas reconnu dans l'expression régulière du while.

    Ensuite on ajoute un peu de code pour traiter ce cas particulier. Ce qui donne:

    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
    17
    18
    19
    20
    while ( $ligne =~ /"([^"]*)"/ ) { 
    		# [^"] est une classe de caractère qui reconnaît tout sauf un guillement (le ^ en début d'une classe de caractère est la négation de tout ce qu'il y a dans la classe).
    		# Donc, /"([^"]*)"/ reconnaît un guillemet, suivi de 0 ou plusieurs caractères autres que des guillemets (autant que possible) suivi d'un autre guillemet. Et
    		# les parenthèses permettent de capturer ce qu'il y a entre les guillemets.
     
              if (defined $1) { # la chaîne entre les guillemets n'est pas vide
     
    			# print "$1\n";
    			print ECRIRE $tab[$i][0] = $i;
    			print ECRIRE $tab[$i][1] = " : ";
    			print ECRIRE $tab[$i][2] = $1;
    			print ECRIRE "\n\n";
    			$i++;
     
    			$ligne =~ s/[^"]+"([^"]+)"//; # Supprime le debut de la ligne jusqu'à ce qui a déjà été reconnu
             } # fin du if (defined ...
             else { # ligne contenant ""
                   $ligne =~ s/[^"]+""//;
             } #fin du else
         } # fin du while

    Voilà, je n'ai pas testé (pas le temps maintenant), mais ça devrait en principe marcher.

    Par ailleurs, ton code de filtrage:

    i
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    f (($ligne =~ /^\t*Left:/) || ($ligne =~ /^\t*Top:/) || ($ligne =~ /^\t*Width:/) || ($ligne =~ /^\t*Height:/)){
    		# ne rien faire
    		print "toto\n";
    	}
    aurait plus sa place à mon avis dans la fonction principale, juste après la ligne:

    en le réécrivant sous la même forme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    next unless /"/;
    next if  /^\t*Left:/ or /^\t*Top:/ or /^\t*Width:/ or  /^\t*Height:/;
    parcourt_ligne ($_);
    ...

  12. #12
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut
    Bonjour,

    Merci pour ton aide.

    J'ai pas mal de problèmes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 73, <FIL
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 71, <FILE_IN> line 18.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 72, <FILE_IN> li
    En testant ça bug toujours quand le code rencontre les "".

    Et j'ai les résultats en double. Il a du mal a récupérer les chaine sur plusieurs lignes, c'est bizarre. Je suis entrain de regarder pourquoi mais je ne vois pas trop.. si tu as le temps, je suis preneur.

    Je crois que ça ne rentre jamais dans le else :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    else{ # ligne contenant ""
    Comme si il trouvait pas de "" alors qu'il y en a bien !

    voici le code avec tes corrections et conseils :

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    use strict;
    use warnings;
     
    my @tab =([0]);
    my $cpt = 0;
    my $i = 0;
     
    $tab[0][0]="ID";
    $tab[0][1]="Ligne";
    $tab[0][2]="Data"; 
     
    my $file_in = "test.apt";
    # my $file_in = "X7_sans_com_sans_desc.apt";
    open FILE_IN, "<$file_in" or die "cannot open $file_in $!";
    open ECRIRE,  '>', "parserExtracteur.txt" or die("Erreur de création de parserExtracteur.txt");
     
    #####################################################################################################################################################################
    #                                                                                                                                                                   #
    # Technique de recherche : reconnaissance progressive avec fusion de la ligne avec la ligne suivante quand on se retrouve avec un seul guillemet et appel récursif  #
    #                                                                                                                                                                   #
    #####################################################################################################################################################################
     
    while (<FILE_IN>) { # Lecture des lignes au fur est à mesure
    	$cpt++;
    	chomp; # Enlève le retour chariot qui pourrait être eventuellement à la fin de la chaine
    	s/\r//; # Enlève retours chariot Windows (compatibilité unix)
    	next unless /"/;  # Elimine les lignes qui ne comporte pas de guillemets
    	next if  /^\t*Left:/ or /^\t*Top:/ or /^\t*Width:/ or  /^\t*Height:/;
    	parcourt_ligne ($_);
    }
     
    sub parcourt_ligne {
    	# L'appel récursif permet de gérer plus facilement les multilignes s'étendant sur plus de seulement 2 lignes, et aussi les cas du genre une
    	# ligne comportant une (ou plusieurs) chaîne(s) + le début d'une chaîne multiligne, ou inversement une ligne avec la fin d'une chaîne multiligne et une ou plusieurs 
    	# chaines,etc...
     
    	my $ligne = shift; 
    	# Récupère le premier élément du tableau par défaut @_, qui contient les paramètres passés à la fonction equivalent à shift @_
     
    	while ( $ligne =~ /"([^"]*)"/ ) { 
    	# [^"] est une classe de caractère qui reconnaît tout sauf un guillement (le ^ en début d'une classe de caractère est la négation de tout ce qu'il y a dans la classe).
    	# Donc, /"([^"]*)"/ reconnaît un guillemet, suivi de 0 ou plusieurs caractères autres que des guillemets (autant que possible) suivi d'un autre guillemet. Et
    	# les parenthèses permettent de capturer ce qu'il y a entre les guillemets.
    		if (defined $1) { # la chaîne entre les guillemets n'est pas vide
     
    			# print "$1\n";
    			print ECRIRE $tab[$i][0] = $i;
    			print ECRIRE $tab[$i][1] = " : ";
    			print ECRIRE $tab[$i][2] = $1;
    			print ECRIRE "\n\n";
    			$i++;
     
    			$ligne =~ s/[^"]+"([^"]+)"//; # Supprime le debut de la ligne jusqu'à ce qui a déjà été reconnu
    		} # fin du if (defined ...
    		else { # ligne contenant ""
    			$ligne =~ s/[^"]+""//;
    		}
    		if ($ligne =~ /"/) { # Cas de guillemet orphelin, donc chaine multiligne
    			my $new_line = <FILE_IN>;
    			chomp $new_line;
    			$new_line =~ s/\s+/ /; # Permet de supprimer les espaces gênants en début de ligne pour les chaînes multilignes.
    			my $line = $ligne . $new_line; # On recupère la ligne suivante
    			parcourt_ligne ($line);
    		}
    	}
    }
    close ECRIRE;
    close FILE_IN;
    J'ai eu ça en sorti :

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    0 : Premiere chaine a recuperer
     
    1 : Deuxieme chaine a recuperer
     
    2 : Quatrieme chaine a recuperer
     
    3 : Cinquieme chaine a recuperer
     
    4 : Cinquieme bis chaine a recuperer
     
    5 : Sixieme chaine a recuperer
     
    6 : Septieme chaine TOTOTOTO TATATA a recuperer sur deux lignes
     
    7 : Sixieme chaine a recuperer
     
    8 : Septieme chaine TOTOTOTO String: E513=
     
    9 :  String: S101 	= 
     
    10 :  String: ENT_Adresse		= 
     
    11 : Cinquieme bis chaine a recuperer
     
    12 : Sixieme chaine a recuperer
     
    13 : Sixieme chaine a recuperer
     
    14 : Cinquieme chaine a recuperer
     
    15 : Cinquieme bis chaine a recuperer
     
    16 : Cinquieme bis chaine a recuperer
    Merci d'avance.

  13. #13
    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
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    il faut remplacer la ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (defined $1) { # la chaîne entre les guillemets n'est pas vide
    par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if ($1 ne "") { # la chaîne entre les guillemets n'est pas vide
    Je pensais que $1 n'était pas défini dans le cas d'une chaîne vide "", mais en fait il est défini comme vide.

    Là, avec les données suivfantes en entrée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    				String: E512="La colonne défaut doit être utilisée."
    				String: E513="Vous n'avez pas les habilitations pour modifier un filtre public."
    				String: S101 	= ""
    				String: ENT_Adresse		= "Adresse"
    				String: ENT_AdresseGeo		= "Adresse geographique
    "

    j'obtiens ceci en sortie:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    cat parserExtracteur.txt
    0 : La colonne défaut doit être utilisée.
     
    1 : Vous n'avez pas les habilitations pour modifier un filtre public.
     
    2 : Adresse
     
    3 : Adresse geographique

  14. #14
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut
    Ah ok,

    Effectivement ça marche bien pour cette exemple.

    Mais le reste n'est plus géré c'est normal ?

    Avec ça en entrée :

    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
    17
    18
    19
    20
    21
    22
    .............................................
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
    		Left: 1.258"
    		Top: 1.258"
    		Width: 1.258"
    		Height: 1.258"
    		"Premiere chaine a recuperer" External References? No
    		Reject "Deuxieme chaine a recuperer" Instances? Yes
    		Enable Runtime "Troisieme
    		chaine a recuperer qui est sur 2 ligne"? No
    		Use Release 4.0 Scope Rules? No
    				Font Name: "Quatrieme chaine a recuperer" gfgfg || "Cinquieme chaine a recuperer" "Cinquieme bis chaine a recuperer"
    				Font Name: "Sixieme chaine a recuperer" gfgfg || "Septieme chaine
    				TOTOTOTO
    				TATATA
    				String: E512="La colonne défaut doit être utilisée."
    				String: E513="Vous n'avez pas les habilitations pour modifier un filtre public."
    				String: S101 	= ""
    				String: ENT_Adresse		= "Adresse"
    				String: ENT_AdresseGeo		= "Adresse geographique"
    J'ai un résultat faux en sortie :

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    0 : Premiere chaine a recuperer
     
    1 : Deuxieme chaine a recuperer
     
    2 : Quatrieme chaine a recuperer
     
    3 : Cinquieme chaine a recuperer
     
    4 : Cinquieme bis chaine a recuperer
     
    5 : Sixieme chaine a recuperer
     
    6 : Septieme chaine TOTOTOTO TATATA String: E512=
     
    7 :  String: E513=
     
    8 :  String: S101 	= 
     
    9 :  String: ENT_Adresse		= 
     
    10 :  String: ENT_AdresseGeo		= 
     
    11 : Sixieme chaine a recuperer
     
    12 : Cinquieme bis chaine a recuperer
     
    13 : Sixieme chaine a recuperer
     
    14 : Sixieme chaine a recuperer
     
    15 : Cinquieme chaine a recuperer
     
    16 : Cinquieme bis chaine a recuperer
     
    17 : Cinquieme bis chaine a recuperer
    Avec ce code et ta correction :

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    use strict;
    use warnings;
     
    my @tab =([0]);
    my $cpt = 0;
    my $i = 0;
     
    $tab[0][0]="ID";
    $tab[0][1]="Ligne";
    $tab[0][2]="Data"; 
     
    my $file_in = "test.apt";
    # my $file_in = "X7_sans_com_sans_desc.apt";
    open FILE_IN, "<$file_in" or die "cannot open $file_in $!";
    open ECRIRE,  '>', "parserExtracteur.txt" or die("Erreur de création de parserExtracteur.txt");
     
    #####################################################################################################################################################################
    #                                                                                                                                                                   #
    # Technique de recherche : reconnaissance progressive avec fusion de la ligne avec la ligne suivante quand on se retrouve avec un seul guillemet et appel récursif  #
    #                                                                                                                                                                   #
    #####################################################################################################################################################################
     
    while (<FILE_IN>) { # Lecture des lignes au fur est à mesure
    	$cpt++;
    	chomp; # Enlève le retour chariot qui pourrait être eventuellement à la fin de la chaine
    	s/\r//; # Enlève retours chariot Windows (compatibilité unix)
    	next unless /"/;  # Elimine les lignes qui ne comporte pas de guillemets
    	next if  /^\t*Left:/ or /^\t*Top:/ or /^\t*Width:/ or  /^\t*Height:/;
    	parcourt_ligne ($_);
    }
     
    sub parcourt_ligne {
    	# L'appel récursif permet de gérer plus facilement les multilignes s'étendant sur plus de seulement 2 lignes, et aussi les cas du genre une
    	# ligne comportant une (ou plusieurs) chaîne(s) + le début d'une chaîne multiligne, ou inversement une ligne avec la fin d'une chaîne multiligne et une ou plusieurs 
    	# chaines,etc...
     
    	my $ligne = shift; 
    	# Récupère le premier élément du tableau par défaut @_, qui contient les paramètres passés à la fonction equivalent à shift @_
     
    	while ( $ligne =~ /"([^"]*)"/ ) { 
    	# [^"] est une classe de caractère qui reconnaît tout sauf un guillement (le ^ en début d'une classe de caractère est la négation de tout ce qu'il y a dans la classe).
    	# Donc, /"([^"]*)"/ reconnaît un guillemet, suivi de 0 ou plusieurs caractères autres que des guillemets (autant que possible) suivi d'un autre guillemet. Et
    	# les parenthèses permettent de capturer ce qu'il y a entre les guillemets.
    		# if (defined $1) { # la chaîne entre les guillemets n'est pas vide
    		if ($1 ne "") { # la chaîne entre les guillemets n'est pas vide	
    			# print "$1\n";
    			print ECRIRE $tab[$i][0] = $i;
    			print ECRIRE $tab[$i][1] = " : ";
    			print ECRIRE $tab[$i][2] = $1;
    			print ECRIRE "\n\n";
    			$i++;
     
    			$ligne =~ s/[^"]+"([^"]+)"//; # Supprime le debut de la ligne jusqu'à ce qui a déjà été reconnu
    		} # fin du if (defined ...
    		else { # ligne contenant ""
    			$ligne =~ s/[^"]+""//;
    		}
    		if ($ligne =~ /"/) { # Cas de guillemet orphelin, donc chaine multiligne
    			my $new_line = <FILE_IN>;
    			chomp $new_line;
    			$new_line =~ s/\s+/ /; # Permet de supprimer les espaces gênants en début de ligne pour les chaînes multilignes.
    			my $line = $ligne . $new_line; # On recupère la ligne suivante
    			parcourt_ligne ($line);
    		}
    	}
    }
    close ECRIRE;
    close FILE_IN;
    J'ai toutes ces erreurs quand je compile :

    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
    17
    18
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 60, <FILE_IN> line 22.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 61, <FILE_IN> line 22.
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 62, <FILE_IN> line 22.
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 60, <FILE_IN> line 22.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 61, <FILE_IN> line 22.
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 62, <FILE_IN> line 22.
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 60, <FILE_IN> line 22.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 61, <FILE_IN> line 22.
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 62, <FILE_IN> line 22.
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 60, <FILE_IN> line 22.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 61, <FILE_IN> line 22.
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 62, <FILE_IN> line 22.
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 60, <FILE_IN> line 22.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 61, <FILE_IN> line 22.
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 62, <FILE_IN> line 22.
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 60, <FILE_IN> line 22.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 61, <FILE_IN> line 22.
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 62, <FILE_IN> line 22.
    Ca te dis quelquechose ?
    Merci encore de l'aide précieuse et de l'intérêt de mon post que tu porte.

  15. #15
    Membre très actif

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Par défaut
    hello,

    juste pour être sûr de bien comprendre, quelle est la définition exacte d'une chaîne entre guillemets ?

    par exemple, comment distinguer la chaine "Troisieme chaine a recuperer..." de la chaine "Top: 1.258" (qui est finalement entre le guillemet à la fin de la première ligne et le guillemet à la fin de la seconde ligne) dans l'exemple ci-dessous ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	Left: 1.258"
    	Top: 1.258"
    	Width: 1.258"
    	Height: 1.258"
    	Enable Runtime "Troisieme
    	chaine a recuperer qui est sur 2 ligne"? No
    Est-ce qu'il ne faut capturer une chaine que lorsque le premier guillemet est suivi (sur la même ligne) de caractères (et non pas d'un saut de ligne par exemple) ?

  16. #16
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut
    Merci de te pencher sur mon problème.

    c'est un cas d'excéption que je gère avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    next if  /^\t*Left:/ or /^\t*Top:/ or /^\t*Width:/ or  /^\t*Height:/;
    Une chaîne c'est le début commençant par " et finissant par ", sur 1 ou plusieurs ligne, et il peut y avoir X chaîne sur la même ligne.

  17. #17
    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
    Billets dans le blog
    1
    Par défaut
    Il y a deux problèmes.

    D'une part, tu n'as pas bien fait la correction que j'ai donnée hier.

    La ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if ($ligne =~ /"/) { # Cas de guillemet orphelin, donc chaine multiligne
    doit venir après la fermeture du while, alors que dans ton coide elle est dans le while.

    Voici le code correct de la fonction parcourt_ligne:

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    sub parcourt_ligne {
    	# L'appel récursif permet de gérer plus facilement les multilignes s'étendant sur plus de seulement 2 lignes, et aussi les cas du genre une
    	# ligne comportant une (ou plusieurs) chaîne(s) + le début d'une chaîne multiligne, ou inversement une ligne avec la fin d'une chaîne multiligne et une ou plusieurs 
    	# chaines,etc...
     
    	my $ligne = shift; 
    	# Récupère le premier élément du tableau par défaut @_, qui contient les paramètres passés à la fonction equivalent à shift @_
     
    	while ( $ligne =~ /"([^"]*)"/ ) { 
    	# [^"] est une classe de caractère qui reconnaît tout sauf un guillement (le ^ en début d'une classe de caractère est la négation de tout ce qu'il y a dans la classe).
    	# Donc, /"([^"]*)"/ reconnaît un guillemet, suivi de 0 ou plusieurs caractères autres que des guillemets (autant que possible) suivi d'un autre guillemet. Et
    	# les parenthèses permettent de capturer ce qu'il y a entre les guillemets.
    		if ($1 ne "") { # la chaîne entre les guillemets n'est pas vide
     
    			# print "$1\n";
    			print ECRIRE $tab[$i][0] = $i;
    			print ECRIRE $tab[$i][1] = " : ";
    			print ECRIRE $tab[$i][2] = $1;
    			print ECRIRE "\n\n";
    			$i++;
     
    			$ligne =~ s/[^"]+"([^"]+)"//; # Supprime le debut de la ligne jusqu'à ce qui a déjà été reconnu
    		} # fin du if (defined ...
    		else { # ligne contenant ""
    			$ligne =~ s/[^"]+""//;
    		}
    	}
    	if ($ligne =~ /"/) { # Cas de guillemet orphelin, donc chaine multiligne
    		my $new_line = <FILE_IN>;
    		chomp $new_line;
    		$new_line =~ s/\s+/ /; # Permet de supprimer les espaces gênants en début de ligne pour les chaînes multilignes.
    		my $line = $ligne . $new_line; # On recupère la ligne suivante
    		parcourt_ligne ($line);
    	}
    }
    Le second problème est que ton fichier en entrée est mal formé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    				Font Name: "Sixieme chaine a recuperer" gfgfg || "Septieme chaine
    				TOTOTOTO
    				TATATA
    				String: E512="La colonne défaut doit être utilisée."
    La septième chaîne n'a pas de guillemet fermant.

    donc, elle se ferme sur le guillement ouvrant suivant. Du coup, à à la fin, il boucle sur la dernière ligne et tu obtiens:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Use of uninitialized value $new_line in scalar chomp at parser_extracteur.pl line 60, <FILE_IN> line 22.
    Use of uninitialized value $new_line in substitution (s///) at parser_extracteur.pl line 61, <FILE_IN> line 22.
    Use of uninitialized value $new_line in concatenation (.) or string at parser_extracteur.pl line 62, <FILE_IN> line 22.
    Avec le programme tel que corrigé ci-dessus et avec le fichier en entrée suivant:

    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
    17
    18
    19
    20
    21
    22
    23
     
    .............................................
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
    		Left: 1.258"
    		Top: 1.258"
    		Width: 1.258"
    		Height: 1.258"
    		"Premiere chaine a recuperer" External References? No
    		Reject "Deuxieme chaine a recuperer" Instances? Yes
    		Enable Runtime "Troisieme
    		chaine a recuperer qui est sur 2 ligne"? No
    		Use Release 4.0 Scope Rules? No
    				Font Name: "Quatrieme chaine a recuperer" gfgfg || "Cinquieme chaine a recuperer" "Cinquieme bis chaine a recuperer"
    				Font Name: "Sixieme chaine a recuperer" gfgfg || "Septieme chaine
    				TOTOTOTO
    				TATATA"
    				String: E512="La colonne défaut doit être utilisée."
    				String: E513="Vous n'avez pas les habilitations pour modifier un filtre public."
    				String: S101 	= ""
    				String: ENT_Adresse		= "Adresse"
    				String: ENT_AdresseGeo		= "Adresse geographique"
    j'obtiens le résultat suivant:

    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
    17
    18
    19
    20
    21
    22
    23
    24
    cat parserExtracteur.txt
    0 : Premiere chaine a recuperer
     
    1 : Deuxieme chaine a recuperer
     
    2 : Troisieme chaine a recuperer qui est sur 2 ligne
     
    3 : Quatrieme chaine a recuperer
     
    4 : Cinquieme chaine a recuperer
     
    5 : Cinquieme bis chaine a recuperer
     
    6 : Sixieme chaine a recuperer
     
    7 : Septieme chaine TOTOTOTO TATATA
     
    8 : La colonne défaut doit être utilisée.
     
    9 : Vous n'avez pas les habilitations pour modifier un filtre public.
     
    10 : Adresse
     
    11 : Adresse geographique
    Ce qui me paraît correct.

    PS: tu as le droit d'approuver (l'icone pouce vers le haut) mes messages qui te rendent service.

  18. #18
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2009
    Messages
    236
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2009
    Messages : 236
    Par défaut
    Bonjour,

    Merci pour toutes ces corrections. J'ai appris pas mal de choses et je t'en remercie.

    Effectivement je t'ai mis le pouce vert sur 95% de tes réponses ^^ Parce que tout est vraiment utile

    Je viens de passer le code sur mon fichier de 600 000 lignes et ça marche presque !!

    j'ai juste cette erreur sur le rappel de la fonction recursive parcourt_ligne ($line); :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 32383.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 53249.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 114244.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 277229.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 291301.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 415208.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 451648.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 464396.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 480554.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 501499.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 501702.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 509839.
    Deep recursion on subroutine "main::parcourt_ligne" at parser_extracteur.pl line 64, <FILE_IN> line 564938.
    a ton avis ça peut venir de quoi ?

    Pour info : Les lignes en questions dans le fichier d'entrée ne comporte pas de "

    Pour exemple
    voici la ligne 32383 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Set hWndResult = SalGetNextChild(hWndResult, nType)
    voici la ligne 53249 :
    Une idée ?

  19. #19
    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
    Billets dans le blog
    1
    Par défaut
    C'est un warning qui te dit: attention, la fonction a été appelée recursivement un grand nombre de fois. A priori, ça n'empêche pas le programme de continuer à fonctionner, sauf que si les appels récursifs continuent à se multiplier, tu risques de finir pas excéder la capacité mémoire de ton ordi.

    Le problème, c'est que ça montre que le programme entre dans un mode multiligne (l'appel récursif n'a lieu qu'en cas de chaîne multiligne) là où il ne devrait sans doute pas.

    Deux raisons possibles pour ces appels récursifs impriqués:
    - un bug subsistant dans le code (je ne pense pas, mais j'ai trop d'expérience en développement pour exclure cette possibilité);
    - un guillemet manquant ou en trop dans une ligne du fichier en entrée entraînant un décalage complet de la recherche.

    Il faudrait que tu analyses le fichier résultat. Tu vas sans doute y trouver ta ligne "Set hWndResult = SalGetNextChild(hWndResult, nType)" au milieu d'un multiligne. Ensuite tu remontes au début de ce multiligne et essaie de voir le problème éventuel dans le fichier en entrée à l'endroit correspondant ou un peu avant.

    Il se peut par exemple que le code "next if /^\t*Left:/ or /^\t*Top:/ or /^\t*Width:/ or /^\t*Height:/;" ne soit pas suffisant et qu'il y ait parfois d'autres balises du même genre avec des " orphelins dont il faudrait écarter les lignes.

  20. #20
    Membre très actif

    Homme Profil pro
    Responsable projets techniques
    Inscrit en
    Février 2003
    Messages
    980
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Responsable projets techniques
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Février 2003
    Messages : 980
    Par défaut
    je voulais proposer une seconde approche : en fait, ce que je comprends, c'est qu'il faut récupérer les chaines de caractères d'un fichier ; une chaine étant définie par un texte entre guillemets sur une ou plusieurs lignes, une ou plusieurs fois par ligne

    en gros, cela revient à dire qu'on alterne des séquences d'affichage (après le premier guillemet) et de non affichage (après le suivant), etc.

    du coup, je suis parti sur un programme qui va découper les données en entrées en fonctions des guillemets, et afficher un élément sur deux ensuite

    un petit exemple vaut mieux qu'un long discours

    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    use strict;
    use warnings;
     
    open my $fh, 'ex.txt';
     
    # flag sert a alterner les chaines
    my $flag=0;
    # str est utilise pour construire la chaine de travail
    my $str='';
     
    # lecture du fichier en sautant les cas particuliers Left/Top...
    while (<$fh>) {
    	next if (/^\s*(?:Left|Top|Width|Height):/);
    	# supression des sauts de lignes et des espaces multiples (pour faire joli uniquement)
    	chomp;
    	s/\s+/ /g;
    	# construction d'une chaine globale de toutes les lignes "intéressantes"
    	$str.=$_;
    }
    # fin d'utilisation du fichier
    close $fh;
     
    #découpage de la chaine par les caractères "
    my @elts=split /"/, $str;
     
    #boucle sur le tableau pour n'en garder qu'un sur deux
    foreach (@elts) {
    	print "$_\n" if $flag;
    	#inversion du flag pour garder un élément sur deux
    	$flag=$flag?0:1;
    }
    Résumé :
    Le programme lit tout le fichier et saute les lignes qui posent problème.
    Il concatène tout le fichier dans une seule chaine en virant les sauts de lignes et en simplifiant les espaces (ça, c'est juste pour faire plus joli)
    Une fois le fichier lu, la chaine générée est découpée en fonction des guillemets et placées dans un tableau.
    Il ne reste qu'à afficher un élément sur deux du tableau...

    Si le fichier est correct (qu'il ne manque pas de guillemets), ça doit marcher (j'ai testé sur les exemples ici).

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Nettoyer les \n entres des guillemets
    Par rambc dans le forum Général Python
    Réponses: 6
    Dernier message: 11/07/2013, 14h05
  2. Rechercher un string entre des guillemets (Expression régulière)
    Par misswatson dans le forum Débuter avec Java
    Réponses: 27
    Dernier message: 22/04/2013, 14h55
  3. Réponses: 2
    Dernier message: 10/01/2012, 23h28
  4. Récupérer valeur entre des balises script
    Par lirycs78 dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 26/10/2010, 14h07
  5. [C# 1.1] Comment récupérer du texte entre des mots connus ?
    Par foolsky dans le forum Windows Mobile
    Réponses: 8
    Dernier message: 26/04/2006, 14h15

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