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 :

[regexp] Remplacer une chaîne par une chaîne aléatoire


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2010
    Messages : 18
    Par défaut [regexp] Remplacer une chaîne par une chaîne aléatoire
    Bonjour,

    J'ai un fichier texte texte.csv à valeurs séparées par des points-virgules :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    "Jean";"Martin";"0123456789";"0600000000";
    "Pierre";"Dupond";"987654321";"0611111111";
    Je cherche à remplacer toutes les chaînes de caractères et tous les chiffres par des chaînes aléatoires et des chiffres aléatoires. J'ai écrit le code 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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    #!/usr/bin/perl -w
     
    if (!open(FIC,"$ARGV[0]")) {
    	print "impossible d'ouvrir $ARGV[0]";
    	exit(1);
    }
     
    my @t;
    my @colonne;
     
    while (defined($l=<FIC>)) {
    	@entree=split(/;/,$l);
    	$no_col=0;
    	foreach $cellule (@entree) {
    		$t[$.][$no_col]=$cellule;
    		$no_col++;
    	}
    }
     
    my @lettres = ( "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" ); 
     
    for my $i (1..scalar(@t)-1) {
    	for my $j (0..$no_col-1) {
    		$_=$t[$i][$j];
    		s/[[:alpha:]]/$lettres[int(rand(scalar(@lettres)-1))]/g;
    		s/[0-9]/int(rand(9))/g;
    		$t[$i][$j]=$_;
    	}
    }
     
    for $i (1..scalar(@t)-1) {
    	for $j (0..$no_col-1) {
    		print "$t[$i][$j];";
    	}
    	print "\n";
    }
    J'obtiens la sortie suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    $ perl remplacement.pl texte.csv
    "qqqq";"jjjjjj";"int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))";"int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))";
    ;
    "jjjjjj";"eeeeee";"int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))";"int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))int(rand(9))";
    ;
    1. Les expressions régulières semblent ne pas évaluer les fonctions (ici, la fonction int(rand(9))). Y a-t-il un moyen de les forcer à le faire ?

    2. À l'intérieur d'une même expression régulière, la fonction rand() n'est calculée qu'une fois. Peut-on la forcer à se rafraîchir, par exemple en insérant le troisième terme de l'expression régulière au sein d'une boucle, quelque chose du type s/[[:alpha:]]/for my $k (0..length($t[$i][$j]) { ... }/g ? Mais je ne vois pas trop comment on pourrait faire...

    3. Pourriez-vous me donner une façon d'écrire ce programme, éventuellement plus concise, plus propre ou plus "perlish" ?

    4. Pourquoi Perl me met-il des "\0;" à chaque fois que je sors de la boucle indexée par $j ?

    5. J'aurais pu écrire scalar(@t)-1 de la façon suivante : $#t. Mais comment écrire le dernier indice de $t[$i] ? $#{$t[$i]} ?


    Merci d'avance,
    endreillie

  2. #2
    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
    J'ai mis dans le code, un certain nombre de commentaires explicatifs.
    Si tu en veux plus, tu peux me les demander.

    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
    #!/usr/bin/perl -w
     
    # INDISPENSABLE
    use strict;
     
    # Utiliser la forme à 3 paramètres de open, et utiliser un filehandle scalaire (my)
    open my $FIC, "<", $ARGV[0] or
      die "impossible d'ouvrir $ARGV[0]: $!\n"; # Ajout de $! donnant la raison de l'erreur
     
    my @t;
    my @colonne;
    my @lettres = ( "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" ); 
     
    # le defined n'est pas utile, en revanche, le my l'est (avec strict)
    while (my $l = <$FIC>) {
      my @entree = split(/;/, $l);
     
      foreach my $cellule (@entree) {
        # Il n'est pas utile de stocker, traiter et écrire le fichier dans trois boucles... autant tout faire ici
        # Pour executer du code dans la partie "remplacement" d'une regexp, il faut ajouter le flag /e
        # Il n'est pas nécessaire d'utiliser $_ pour appeler l'opération s///, il suffit d'utiliser l'opération =~
        $cellule =~ s/[[:alpha:]]/$lettres[int(rand(scalar(@lettres)-1))]/ge;
        $cellule =~ s/[0-9]/int(rand(9))/ge;
      }
      # Il n'est pas nécessaire de boucler avec un for pour parcourir un tableau, ou l'afficher
      print join ";", @entree;
    }
    On peut faire nettement plus court, bien sur. Si le sujet t'intéresse, je m'y penche volontiers.

  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 : 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
    Un détail : dans les substitutions actuelles, le caractère "z" et le digit 9 ne sont jamais utilisés. Il faut légèrement modifier les limites hautes de rand pour qu'ils soient autorisés.
    (j'en suis à 5 lignes de code, dont la ligne "use strict" ; accessoirement, il est possible de gagner de réaliser cela en uniligne également à l'aide de seulement 2 instructions et les bonnes options).

  4. #4
    Membre averti
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2010
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2010
    Messages : 18
    Par défaut
    Bonjour,

    Citation Envoyé par Philou67430 Voir le message
    Un détail : dans les substitutions actuelles, le caractère "z" et le digit 9 ne sont jamais utilisés. Il faut légèrement modifier les limites hautes de rand pour qu'ils soient autorisés.
    Pourtant je croyais que rand(n) renvoyait un réel entre 0 et n. Ta remarque tiendrait-elle la "densité" de n dans [0,n] est nulle, donc que la probabilité que rand(n) renvoie n est nulle, donc que l'événement rand(n)=n est quasi-impossible, donc que 0 <= int(rand(n)) <= n-1 ?

    Dans ce cas suffit-il de mettre int(rand(10)) dans mon code ? Mais il faut peut-être quand même se protéger du cas où par miracle rand(10) renverrait 10, donc ça donnerait quelque chose du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    $randnb=rand(10);
    if ($randnb==10) {
        $randnb=9;
    }
    Suis-je dans le vrai ?

    Citation Envoyé par Philou67430 Voir le message
    (j'en suis à 5 lignes de code, dont la ligne "use strict" ; accessoirement, il est possible de gagner de réaliser cela en uniligne également à l'aide de seulement 2 instructions et les bonnes options).
    Je suis curieux de voir ça.

    Cordialement,
    endreillie
    Étudiant 1re année mathématiques-informatique

  5. #5
    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
    Citation Envoyé par endreillie Voir le message
    Pourtant je croyais que rand(n) renvoyait un réel entre 0 et n.
    ...
    Suis-je dans le vrai ?
    Non.
    Quand tu as un doute sur une fonction, il convient de regarder la documentation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    perldoc -f rand :
           rand EXPR
           rand    Returns a random fractional number greater than or equal to 0
                   and less than the value of EXPR.  (EXPR should be positive.)
    Dans ce contexte, rand(10) retournera toujours une valeur de l'intervalle [0, 10[ et int(rand(10)) retournera un chiffre de 0 à 9.
    Je suis curieux de voir ça.
    Sous forme de script :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/usr/bin/perl -w
     
    # INDISPENSABLE
    use strict;
     
    # Inutile d'ouvrir les fichiers en paramètre du script (en utilisant l'opérateur <>)
    while (<>) {
      s/[[:alpha:]]/chr(ord("a")+int(rand(26)))/ge;
      s/[0-9]/int(rand(10))/ge;
      print;
    }
    Sous forme d'utiligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perl -pe 's/[[:alpha:]]/chr(ord("a")+int(rand(26)))/ge;s/[0-9]/int(rand(10))/ge;' texte.csv

  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
    Pour rand(10), essaye cet uniligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perl -e 'while (int(rand(10)) != 10) {} ; print "rand(10) = 10\n"'
    S'il te rends la main, j'aurais dit une bêtise (et la doc aussi)

Discussions similaires

  1. [XL-2007] [FORM] remplacer la valeur d'une cellule par une autre
    Par coldavires dans le forum Excel
    Réponses: 7
    Dernier message: 21/01/2010, 22h34
  2. Remplacer une lettre par une autre dans une cellule
    Par Philippe76 dans le forum Excel
    Réponses: 1
    Dernier message: 09/01/2010, 21h26
  3. [PROC] Remplacer un point par une virgule dans une Proc Tabulate
    Par PAULOM dans le forum SAS Base
    Réponses: 2
    Dernier message: 20/08/2009, 08h36
  4. [Toutes versions] Remplacer "#N/A" par une valeur par défaut
    Par canary dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 10/05/2009, 11h23
  5. [RegEx] Remplacer dernière occurence d'une chaine par une autre
    Par webjoujou dans le forum Langage
    Réponses: 3
    Dernier message: 12/11/2008, 17h58

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