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 :

Question de Langage [RegEx & subroutines)


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2010
    Messages : 12
    Par défaut Question de Langage [RegEx & subroutines)
    Hello à tous,

    Ca toujours fait plaisir de revenir dire bonjour de temps à autre sur le forum Perl.
    Terre d'attache, hameau de paix et d'avis éclairés sur cet incroyable
    couteau suisse qu'est Perl. Cela me rappelle qu'hier,
    j'ai échappé de justesse à une bande errante de programmeurs Python partis
    en chasse. ( oui, oui, je vous jure ... )

    Mais là n'est pas le débat, je me pose une question au caractère presque "existentiel" ...
    Imaginons ce bout de code suivant qui tente
    de récupérer une balise du genre <date_mois= xxxxx> dans
    un fichier.txt et qui tente de la stocker dans un tableau.

    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
     
    [...]
     
    open( READ, "<:encoding(utf8)", "read.txt" ) || die("Erreur");
    my @date_jourmois;
     
    while (<READ>) {
          push(@date_jourmois, &regEx_pushTab($_,"date_jourmois"));
     
    }
    close (READ);
     
    sub regEx_pushTab{
          my $string = $_[0];
          my $regex = $_[1];
     
          my @temp_date = ( $_ =~ /<$regex=(.+?)>/g );
     
         return @temp_date;
    }
     
    [...]
    En gros, ce script fait en 10 lignes ce que je pourrai faire en
    deux dans la "main code", cependant j'aimerais comprendre.
    Pourquoi le script, une fois exécuté, me renvoie-t-il une erreur
    de compilation de RegEx ?

    Est-ce parce que :
    Il ne faut pas appeler une fonction dans une opération
    telle que push?
    Ma regex dans ma fonction est mal écrite et devrait plutôt
    ressembler à quelque chose comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    my $regex = <$regex=(.+?)>;
    [...]
    sub regEx_pushTab{
         my $regex = $_[0];
         my @temp_date = ( $_ =~ /$regex/g );
    }
    voire ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    sub regEx_pushTab{
         my $regex = $_[0];
         my @temp_date = ( $_ =~ /\Q$regex/g );
    }
    Pire encore, la grammaire formelle de mon interpréteur a-t-elle dégénérée à force de RegEx à tour de bras et a-t-elle sombré définitivement dans l'obscurantisme ?

    Qu'en pensez-vous ?
    Y-a-t-il des formulations que Perl accepte à la ""compilation""
    (remarquez les guillemets) et qui le font immanquablement planter lors de l'exécution?

    Sur cette grande recherche métaphysique et presque linguistique, je vais dormir

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Août 2008
    Messages
    505
    Détails du profil
    Informations personnelles :
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Août 2008
    Messages : 505
    Par défaut
    Les forces obscures sont probablement à l'oeuvre. Toutefois, il y a des éléments que je ne comprends pas dans ton script. Par exemple,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    sub regEx_pushTab{
          my $string = $_[0];
          my $regex = $_[1];
          my @temp_date = ( $_ =~ /<$regex=(.+?)>/g );
         return @temp_date;
    }
    Pourquoi n'est-ce pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     $string =~ /<$regex=(.+?)>/g
    . Ce serait plus propre.

    Ensuite, pourquoi renvoies-tu un tableau ? tu vas avoir un tableau de tableau ! Est-ce voulu ?

    Pourquoi dis-tu que tu cherches des éléments <date_mois= xxxxx> alors que dans ton code tu utilise un pattern date_jourmois ? Est-ce une simple typo ?

    Et dernière interrogation, le script que tu donnes fonctionne chez moi (au moins sommairement). Même en utilisant use strict.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2010
    Messages : 12
    Par défaut En effet, les force obscures de Perl nous dépassent.
    Hello

    En effet, je me complique un peu la vie.
    Je vais être plus concis :
    Mon script doit retrouver dans un fichier texte des
    occurrences entre des balises.

    Ces occurrences ont la forme suivante :
    <date_mois=29 juin 2010> ou encore
    <date_enumjourmois=le 12, 13 et 14 février 2010> et il y en a plusieurs par ligne.


    Et ensuite, j'aimerais qu'il stocke au fur à mesure qu'il parcourt le fichier.txt ce qu'il y a à l'intérieur
    de ces balises dans un tableau du même nom que la balise, du genre @date_mois.

    Vu que j'ai énormément de balises dans le texte, j'essaye
    de faire en sorte de résumer mon code à une seule ligne, d'où
    ma fonction regEx_pushTab.

    Histoire qu'à la fin mon code ressemble à truc genre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    open( READ, "<:encoding(utf8)", "read.txt" ) || die("Erreur");
    @date_jourmois;
     
    while (<READ>) {
          # Une seule "belle" ligne pour une seule balise.
          push(@date_jourmois, &regEx_pushTab($_,"date_jourmois"));
     
    }
    close (READ);
    Et que la fonction regEx_pushTab me donne
    à la fin du while, un tableau @date_jourmois où tous les patterns
    entre balises y soient stockés.


    Si je me complique la vie, c'est parce que, comme je l'ai dit plus haut,
    il y a énormément de balises à retrouver dans le texte et, comme
    je déteste copier-coller mon code
    , je préfère une solution "générique".
    Heureusement, travaillant sous Unitex, j'ai construit des graphes en faisant bien en sorte d'éviter des balises croisées.

    Or, pour te répondre Thierry, le problème avec ma regex
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     $string =~ /<date_mois=(.+?)>/g
    c'est qu'elle ne prend que la première occurrence qui apparaît sur une ligne
    et ne "match" pas les suivantes, et ce malgré l'option "global".
    Du coup, l'idée de stocker directement les "matched" dans un tableau fonctionne assez bien.

    Cependant, je peux me tromper.
    Je vous fournis un exemple de "read.txt" en fichier attaché
    (en UTF8, of course ) qui fournira exemple du genre de texte
    que je vais être amené à traiter.


    Une dernière chose : Renvoyer un tableau en return de fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    [...]
    return @tab;
    }
    Est-ce pas conseillé ? Est-ce préférable à une référence ?
    Est-ce non préférable à une référence ? Etc ..


    Bon début de soirée à vous tous.
    Fichiers attachés Fichiers attachés

  4. #4
    Membre chevronné
    Avatar de Schmorgluck
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    371
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2006
    Messages : 371
    Par défaut
    Pourquoi, dans ta subroutine, déclares-tu une variable $string où mets le premier élément de @_, et dont tu ne te sers pas ?

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2010
    Messages : 12
    Par défaut Résolution du problème.
    Hello,

    En effet, Thierry.chich, certaines erreurs se sont glissées dans mon dernier message.
    A force de réduire le code pour le présenter brièvement dans un simple Topic, on accroit les risques d'erreurs.
    Pour apporter une contribution à la communauté, j'offre ici la méthode avec laquelle j'ai pu résoudre mon problème.

    Ce n'est peut-être pas la meilleure mais elle répond à mes besoins.
    Si vous avez des améliorations à y apporter, n'hésitez pas à m'en faire part.

    Pour rappel :
    1) A la lecture d'un fichier .txt mon script devait repérer des balises
    et stocker leur contenu.
    2) Il y avait plusieurs fois la même balises par ligne.
    3) Il y avait de très nombreuses balises différentes, donc
    mon script devait permettre l'ajout d'une nouvelle forme à retrouver
    sans devoir pour autant écrire plus d'une ligne de code.
    4) Ces balises étaient générées auparavant par le passage de mon fichier .txt par une grammaire ( construite à l'aide du logiciel Unitex ).


    CODE :
    Fonction principale
    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
    69
    70
    71
    72
    73
    74
    75
    76
    sub readOutput {
    	open( READ, "<", "output.txt" ) || die("Erreur");
    	binmode( READ, ":encoding(utf8)" );
     
    	# Liste des noms de balises à retrouver
    	# ex : <date_jourmoislieu=xxxxxx>
    	my @tab_pattern = (
    		"option",          "date_jourmois",
    		"date_jourmoislieu",  "date_jourmoisannee",
    		"date_enumjourmois",  "date_range_jourjourmois",
    		"date_det_jour",      "date_det_jourmois",
    		"date_annee",         "heure_rdv",
    		"heure_aheure",       "heure_lieu",
    		"sujet_mot",          "sujet_demande",
    		"sujet_verre",        "sujet_rdv",
    		"sujet_heurelieu",    "mixte_jourmoisheure",
    		"lieu_dans",          "lieu_au",
    		"lieu_lieudate",      "lieu_lieudateheure",
    		"referent_jour",      "referent_journb",
    		"referent_jourheure", "referent_jourlieu",
    		"referent_joursujet", "referent_journbheure",
    		"referent_heurejour", "sujet_motdate",
    		"sujet_motpays", 	  "referent_journbmois",
    		"referent_sujet", 	  "lieu_chez",
    		"lieu_adresse",		  "lieu_ifadresse",
    		"canon_rdvlieu",	  "canon_disons",
    		"canon_rdv_aupire",	  "heure_convenir",
    		"referent_indice",    "heure_range_unique",
    		"lieu_auditoire",	  "canon_rdvheure",
    		"sujet_motdateheure", "canon_propose"
    	  );
     
     
    	my $pattern_taille = @tab_pattern;
    	my %hash_match = ();
    	my $count = 0;
     
            # Lecture du fichier .txt
    	while (<READ>) {
    		# Imprime le contenu du fichier
    		print($count . " : " . "$_" );
    		$count++;
     
     		# Utilisation des noms de balises.
    		foreach my $pattern ( @tab_pattern ){
     
    			# Si la balise existe déjà dans la table de Hash,
    			# on récupère le tableau qui y était précédemment, 
    			# on y ajoute les nouvelles formes "matchées" 
    			# et on stocke à nouveau le tableau dans la hash.
    			if ( exists $hash_match{$pattern} ) {
    				if ( $_ =~ /<$pattern=/  ){
    					my @tab_temporaire = &push_tab ( $_, $pattern );
    					my @tab_yet_present = @{$hash_match{$pattern}};
    					push(@tab_yet_present, @tab_temporaire);
    					$hash_match{$pattern} = \@tab_yet_present;
    				}
    			}
    			# Lorsqu'une ligne continent une des balises,
    			# on récupère son contenu que l'on met dans un tableau
    			# et on stocke la référence de ce tableau dans la table de Hash.
    			else {
    				if ( $_ =~ /<$pattern=/ ){
    					my @tab_temporaire = &push_tab( $_, $pattern );
    					$hash_match{$pattern} = \@tab_temporaire;
    				} 
    			}
    		}
    	}
    	close(READ);
     
    	# On affiche le contenu des tableaux.
    	foreach my $k (keys(%hash_match)){
       		&toStringTab( "$k : ", $hash_match{$k} );
    	}	
    }
    Les deux fonctions appelées
    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
     
    # Récupère le contenu des balises retrouvées dans la ligne lue
    sub push_tab {
    	my $string = shift;
    	my $regex  = shift;
     
    	my @temp_date = ( $_ =~ /<$regex=(.+?)>/g );
     
    	return @temp_date;
    }
     
    # Affiche les tableaux qui ne sont pas vides
    sub toStringTab {
    	my $string       = shift;
    	my $de_ref       = shift;
    	my @tab_toString = @$de_ref;
     
    	my $taille = @tab_toString;
    	if ( $taille > 0 ) {
    		$string =~ tr/a-z/A-Z/;
    		print("\n$string\n");
    		foreach my $m (@tab_toString) { print "$m\n"; }
    	}
    }
    Bonne soirée à vous tous.

  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 : 59
    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
    Par défaut
    Les balises peuvent-elles s'étendre sur plusieurs lignes ?
    Si ce n'est pas le cas, voici un uniligne qui, me semble-t-il, répond au besoin (si j'ai bien compris le besoin) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ cat read.txt | perl -MData::Dumper -ne 'map { ($tag,$val) = split /\s*=\s*/;push @{$tag{$tag}}, $val } /<([^>]+)>/g; END { print Data::Dumper->Dump([\%tag], [qw(*tag)]); }'
    %tag = (
             'date_det_jour' => [
                                  'le 5'
                                ],
             'date_jourmois' => [
                                  '15 octobre',
                                  '8 octobre'
                                ],
             'date_enumjourmois' => [
                                      'les 15 et 29 octobre'
                                    ]
           );

  7. #7
    Membre chevronné
    Avatar de Schmorgluck
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    371
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2006
    Messages : 371
    Par défaut
    Citation Envoyé par SonyBlack Voir le message
    Les deux fonctions appelées
    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
     
    # Récupère le contenu des balises retrouvées dans la ligne lue
    sub push_tab {
    	my $string = shift;
    	my $regex  = shift;
     
    	my @temp_date = ( $_ =~ /<$regex=(.+?)>/g );
     
    	return @temp_date;
    }
     
    # Affiche les tableaux qui ne sont pas vides
    sub toStringTab {
    	my $string       = shift;
    	my $de_ref       = shift;
    	my @tab_toString = @$de_ref;
     
    	my $taille = @tab_toString;
    	if ( $taille > 0 ) {
    		$string =~ tr/a-z/A-Z/;
    		print("\n$string\n");
    		foreach my $m (@tab_toString) { print "$m\n"; }
    	}
    }
    Je ne comprends toujours pas à quoi sert $string dans push_tab. J'ai l'impression que c'est une grosse partie de ton problème. Essaie cette nouvelle version de push_tab, qui a le mérite de se servir de $string :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    sub push_tab {
    	my $string = shift;
    	my $regex  = shift;
     
    	my @temp_date = ( $string =~ /<$regex=(.+?)>/g );
     
    	return @temp_date;
    }

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

Discussions similaires

  1. [Questions]Le langage de programmation Binaire existe t-il ?
    Par Nasky dans le forum Langages de programmation
    Réponses: 30
    Dernier message: 16/11/2012, 09h09
  2. Question sur les Regex. interdire une chaine
    Par cysboy dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 20/05/2007, 13h49
  3. Questions sur une Regex
    Par mpereg dans le forum Général Python
    Réponses: 7
    Dernier message: 09/03/2007, 19h50
  4. Question sur les regex, besoin d'une lumière
    Par Cladjidane dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 09/03/2007, 12h28
  5. question sur langage
    Par nemo69500 dans le forum Windows
    Réponses: 7
    Dernier message: 01/12/2006, 23h45

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