[PERL expreg] capture optionnelle ou EOL

Résolu
Bonjour,

Je cherche à capturer un élément de manière optionnel :

A1F712492D9B|info_46943_0_11111@domaine.com
C55657BC738|info_48894_0_22222@domaine.com|20100826_121900


aujourd'hui je fais :
while (<FICHIER_HOLD>) {
	(($clef,$valeur) = /([^|]+)\|(.*)$/i);
}

qui me prend bien clef et valeur selon le |, mais je souhaiterais ajouter un élément optionnel correspondant à une date heure (ligne 2 de l'exemple) présente ou non après un |, j'ai bien bricoler un peu mais sans succès :

([^|]+)\|([^|]+)\|([^|]+)


pourtant j'ai bien lu le bouquin sur les expressions régulières ... ça doit pas être sorcier ...

Merci d'avance pour votre aide !

Stéphane

6 réponses

  1. Modérateur
    Re,

    Oups, j'ai fait une erreur. Quand on mets les "" alors split considére qu'il s'agit d'une chaine de caractères. Donc c'est /\|/ et pas "/\|/"

    Ensuite il faut juste faire un test pour print comme ça plus des warnings.

    ~ $ cat champs_underscore.pl
    #!/usr/bin/perl  
    use strict;use warnings;  
    
    while (<DATA>) {  
      my ($clef,$valeur,$datehold) = split /\|/;  
      if($datehold){  
        print "clef : $clef  valeur : $valeur  datehold : $datehold\n";  
      }else{  
        print "clef : $clef  valeur : $valeur\n";  
      }  
    }  
    
    __END__  
    A1F712492D9B|info_46943_0_11111@domaine.com  
    C55657BC738|info_48894_0_22222@domaine.com|20100826_121900  
    
    ~ $ perl champs_underscore.pl 
    clef : A1F712492D9B  valeur : info_46943_0_11111@domaine.com  
    
    clef : C55657BC738  valeur : info_48894_0_22222@domaine.com  datehold : 20100826_121900


    GNU/Linux:Linux is Not Ubuntu! Quel linux choisir ne veut pas dire votre Distribution préférée,
    106485010510997108
    1. Modérateur
      Re,

      Tu peux aussi utiliser l'opérateur ?: si tu veux, pour faire plus court ;-)

      #!/usr/bin/perl
      use strict;use warnings;
      
      while (<DATA>) {
        my ($clef,$valeur,$datehold) = split /\|/;
        $datehold
        ?
          print "clef : $clef  valeur : $valeur  datehold : $datehold\n"
        :
          print "clef : $clef  valeur : $valeur\n"
        ;
      }
      
      __END__
      A1F712492D9B|info_46943_0_11111@domaine.com
      C55657BC738|info_48894_0_22222@domaine.com|20100826_121900
      
    2. excellent, le print n'est là que pour faire jolie, je vais stocker en tableau uniquement les entrées de moins de 2 jours et donc purger les autres.
      Je vais donc parser la datehold et la matcher, DateTime est mon ami !

      Merci beaucoup à tout les 2 !!

      Stéphane
  2. parfais, non il n'y aura pas d'espace, j'aurais jamais pensé à utilisé l'espace !

    bravo

    maintenant je test en live sur un fichier ... monstrueux :)

    a+

    Stéphane
    1. Modérateur
      Re,

      Tu n'as pas répondu à ma question ;-)
  3. Modérateur
    Salut,

    Si j'ai bien compris, quelque soit le nombre de champs tu veux récupérer juste les 2 premiers?
    1. bonjour lami,

      non, je veux récupérer soit 2 champ soit 3 si le 3eme est présent.

      2 formats possible pour chaque ligne :

      champ1|champ2
      ou
      champ1|champ2|champ3

      quand le champ3 n'existe pas, la variable vaut rien ou vide :

      (($clef,$valeur,$datehold) = ([^|]+)\|([^|\s]+)(?:\|([^\s]+))?

      ça me parait pas mal ....

      Stéphane
    2. Modérateur
      Re,

      Pour ce genre de situation split doit faire l'affaire vu qu'il y a un séparateur de champs.
      Perso c'est comme ça que j'aurais fait (même si j'aime bien les regex ;-)

      ($clef,$valeur,$datehold) = split "/\|/";
    3. ça marche pas .... pourtant c'est plus logique et simple que l'expression régulière ....

      while (<FICHIER_HOLD_FROM>) {
              ($clef,$valeur,$datehold) = split "/\|/";
      	print "clef : $clef  valeur : $valeur  datehold : $datehold\n";
      }
      


      donne :

      Use of uninitialized value in concatenation (.) or string at /repertoire/fichier.pl line 112, <FICHIER_HOLD> line 1.
      Use of uninitialized value in concatenation (.) or string at /repertoire/fichier.pl line 112, <FICHIER_HOLD_FROM> line 1.
      clef : C55657BC738|infos_00000_0_111111@domaine.com
        valeur :   datehold :
      
      


      avec la source :

      # cat fichier_hold.dat
      C55657BC738|infos_00000_0_111111@domaine.com
      ...
      
  4. Après quelques essai je te propose ceci : ([^|]+)\|([^|\s]+)(?:\|([^\s]+))?
    Cela devrait marcher si tes champs entre pipe ne contiennent pas d'espaces, sinon ca va être plus compliqué...
    1. je viens de tester avec The Regex Coach et ça ne semble pas faire ce que j'attends.

      si je test sur une ligne avec uniquement 2 éléments, il poursuit sur la seconde ligne pour finir le second token.

      si je test sur une ligne avec 3 éléments, il va finir le 3eme token sur la ligne suivante ....

      au secours ...

      Stéphane
      1. Essaye Avec un regex de type ([^|]+)\|([^|]+)(?:\|([^|]+))?
        (?: ) = parenthèse non capturantes.