Remplacer caractères héxa : PERL

Remplacer caractères héxa : PERL - Perl - Programmation

Marsh Posté le 29-07-2010 à 10:33:38    

Bonjour,
 
Je veux remplacer plusieurs caractères hexa (plus de 2) par un ou plusieurs autres caractères héxa avec perl.
 
Exemple :
remplacer 0D0A46 par 45
 
Apparement avec \x sous perl ça marche que pour un seul caractère hexa!
 
Avez-vous des solutions?
 
 
Merci

Reply

Marsh Posté le 29-07-2010 à 10:33:38   

Reply

Marsh Posté le 29-07-2010 à 13:55:01    

$machaine =~ s/\x0D\x0A\x46/\x45/g;
A+,

Message cité 1 fois
Message édité par gilou le 29-07-2010 à 13:55:16

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 29-07-2010 à 20:32:01    

gilou a écrit :

$machaine =~ s/\x0D\x0A\x46/\x45/g;
A+,


merci mais ça ne marche pas.
 
Pour tester j'ai créer un programme en vert ça marche en rouge ça marche pas.  
Donc un hexa ok plus de 2 pas ok

Code :
  1. #!/usr/bin/perl -w
  2. use strict;
  3. $| = 1;
  4. my ($f);
  5. print "Chemin fichier: " and chomp($f = <STDIN> );
  6. open FIC, $f or die "$f : $!\n";
  7. open FILE, '>tmp.txt' or die "tmp.txt : $!\n";
  8. my $i = 1;
  9. while (<FIC> ) {   
  10.       s/\x01/\x45/g;
  11.       s/\x01\x0D\x46/\x45/g;
  12.       print FILE ; 
  13.    $i++;
  14. }
  15. close FIC and close FILE;
  16. unlink $f;
  17. rename "tmp.txt", $f;
  18. print "ok";


Rmq : J'utilise PsPad pour écrire des hexa. D'abord j'écris n'importe quoi dans mon fichier puis je remplace avec PsPadHEX certains caractères.


Message édité par perly le 29-07-2010 à 20:33:23
Reply

Marsh Posté le 29-07-2010 à 21:08:32    

:hello:
Bien sur que la, ca va pas marcher, puisque tu ouvres ton fichier en mode ligne à ligne, et que dans ton pattern recherché, il y a un caractère de fin de ligne (\x0A)  :sarcastic: (tes hexa substitués, c'est "\r\nF" ).
Il n'a été dit nulle part dans ta présentation initiale du problème, que ce que tu voulais substituer provenait d'une boucle de lecture de fichier, et vu qu'il y avait un \n au milieu de ton pattern cherché, il semblait même illogique que ce soit le cas.

 

Tu as deux possibilités:
Soit tes fichiers sont petit en mémoire, et tu lis tout ton fichier dans une variable texte pour lui appliquer la substitution:

Code :
  1. {
  2.    local( $/ ) ;
  3.    open( my $fh, $file ) or die "cannot open file $f\n"
  4.    binmode $fh; #sous dos windows, \r\n est transformé en \n automatiquement si on en fait pas ça
  5.    $text = <$fh>
  6.    $text =~ s/\x0D\x0A\x46/\x45/g;
  7.    # ? print $text qque part
  8. }
 

Soit il faut avancer ligne a ligne et éclater ton pattern recherché en deux, celui avant  la fin de ligne /\r\n$/ et celui après /^F/
et faire de une boucle qui teste lorsqu'une ligne a le bon pattern, si la ligne suivante l'a aussi on fait la substitution.
C'est plus coton (il faut mémoriser la ligne précédente et ne pas l'envoyer tout de suite en sortie) mais pas bien dur.
Ne pas oublier la aussi le binmode après ouverture du fichier, sinon, on ne verra jamais passer un \x0D\x0A.

 

A+,


Message édité par gilou le 29-07-2010 à 21:40:29

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 02-08-2010 à 12:22:38    

Merci pour ta réponse.  
 
J'ai trouvé :sol: , c'était très simple en fait. Dans perl il suffit de rajouter des crochets entre \r\n [\x0D\x0A]
 

Code :
  1. #!/usr/bin/perl -w
  2. use strict;
  3. $| = 1;
  4. my ($f);
  5. print "Chemin fichier: " and chomp($f = <STDIN> );
  6. open FIC, $f or die "$f : $!\n";
  7. open FILE, '>tmp.txt' or die "tmp.txt : $!\n";
  8. while (<FIC> ) { 
  9.       s/\x01[\x0D\x0A]/\x45/g;
  10.        print FILE ;
  11. }
  12. close FIC and close FILE;
  13. unlink $f;
  14. rename "tmp.txt", $f;


 
 

Reply

Marsh Posté le 02-08-2010 à 13:50:47    

Citation :

il suffit de rajouter des crochets


Euh non, c'est juste totalement faux, ça.
C'est pas la même expression régulière:
\x01[\x0D\x0A]  c'est la même chose que \x01(\x0D|\x0A) c'est à dire \x01(\r|\n) et c'est donc pas du tout pareil que \x01\r\n
L'écriture entre [] n'a d'intérêt que si on fait un range [\x0A-\x0D] ou une négation [^\x0A]

 

Pourquoi le code que tu as écrit a des chances de marcher (sous dos windows)
1) manifestement, tu n'ouvres pas le fichier en mode binaire, donc les \r\n sont remappés par perl automatiquement en \n
donc tu remplacerait ton expression x01[\x0D\x0A] par x01\x0A que ça marcherait pareil
Donc effectivement, après ce remappage automatique, si on veut chercher ce qui est comme \x01\r\n dans le fichier, il va falloir chercher \x01\n
Et comme maintenant, avec ton \x01[\x0D\x0A] tu ne cherches plus comme avant \x01\x0D\x0A mais \x01(\x0D|\x0A) ce qui équivaut à (\x01\x0D|\x01\x0A) la seconde alternative \x01\x0A ie \x01\n va matcher ton \x01\r\n après le remappage de perl en \x01\n
Si tu avais lu ma réponse précédente et ouvert le fichier en mode binaire, il y aurait pas de remappage, et chercher \x01\x0D\x0A marcherait très bien.
2) ce coup ci, en mode lecture ligne à ligne, tu ne cherches plus une expression régulière avec un \n au milieu (ce qui ne pouvait pas être matché), mais avec un \n à la fin
Donc effectivement, ce coup ci, ça va pouvoir être matché, contrairement à ce que tu faisais avant (ou tu voulais un \x46 en début de ligne suivante)

 

Donc si ça marche maintenant, c'est pas du tout pour les raisons que tu donnes.

 

A+,


Message édité par gilou le 02-08-2010 à 13:52:39

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 02-08-2010 à 17:36:17    

Autant pour moi!
Je te remercie pour tes explications d'expert.
 
Donc si j'ai un \n au milieu de l'expression régulière je procède comment?
 
Par exemple si j'ai FR\r\nANG que je veux remplacer par FR\r\nENG
 
je procède comme cela car ça n'a pas l'air de marcher :  
 

Code :
  1. ...
  2. open FIC, $f or die "$f : $!\n";
  3. binmode $f;
  4. ...
  5. while (<FIC> ) { 
  6.        s/FR\x0D\x0AANG/FR\x0D\x0AENG/g;
  7.     $i++;
  8. }
  9. ...


 
Merci.
A+

Reply

Marsh Posté le 02-08-2010 à 19:53:08    

Comme je te l'ai dit, tu peux pas si tu as ça dans une lecture ligne a ligne, car ton while (<FIC> ) va d'abord chopper le FR\r\n puis le ANG puisque ça lit ligne à ligne.

 

Comme je te l'avais indiqué, il y a deux méthodes:
Tout lire dans une seule grande ligne (pas possible si le fichier est trop gros).
On fait

 
Code :
  1. {
  2.    local( $/ ) ;
  3.    open( my $fh, $file ) or die "cannot open file $f\n"
  4.    binmode $fh; #sous dos windows, \r\n est transformé en \n automatiquement si on en fait pas ça
  5.    $text = <$fh>; # lit tout d'un coup
  6.    $text =~ s/FR\r\nANG/FR\r\nENG/g;
  7.    # ? print $text qque part
  8. }


1) on met dans un bloc {} sinon, ça risque de foutre le bordel ailleurs
2) on fait local( $/ ) ;  pour lire sans s'arrêter a chaque \r\n (windows) ou \n (unix) cette redéfinition étant limitée au bloc
3) on lit tout en un seul coup dans une variable
4) on fait le remplacement sur le contenu de la variable
5) on sauve la variable modifiée dans le fichier de sortie.

 

L'autre méthode, c'est de procéder en deux temps; On cherche /FR\r\n$/ et quand on a trouvé ça, on le mémorise pour voir si la ligne suivante commence par /^ENG/ et si oui, on fait le remplacement:

 
Code :
  1. my $found = 0;
  2. my $ligprec = "";
  3. while ( <FH> ) {
  4.    if ($found) {
  5.        if (/^ANG/) {
  6.            # On a matché le pattern cherché
  7.            # on fait ce qu'on veut sur $ligprec et $_ en fonction de ses besoins
  8.            ############################################################################
  9.            # ici, c'est juste la deuxième ligne qu'on modifie
  10.            # on ne fait rien a la ligne sauvegardée, donc on va l'imprimer telle quelle
  11.            print $ligprec;
  12.            # On fait la modif
  13.            s/^ANG/ENG/o;
  14.            ############################################################################
  15.        }
  16.        else {
  17.            # pas trouvé, donc on imprime la ligne sauvegardée
  18.            print $ligprec;
  19.        }
  20.        #reset des variables de sauvegarde
  21.        $found = 0;
  22.        $ligprec = "";
  23.    }
  24.    if (/FR\r\n$/) {
  25.        $found = 1;
  26.        # On sauvegarde la ligne
  27.        $ligprec = $_;
  28.        #on boucle sans l'imprimer
  29.        next;
  30.    }
  31.    else {
  32.        print;
  33.    }
  34. }
  35. if ($found) {
  36.    # la derniere ligne du fichier se terminait FR\r\n et a été sauvegardée
  37.    # on imprime cette ligne sauvegardée
  38.    print $ligprec;
  39. }


Note que j'ai fait du code pédagogique, mais perso, ce serait my $ligprec; en ligne 2 et undef $ligprec; en ligne 22 que j'écrirais dans du vrai code.
A+,


Message édité par gilou le 02-08-2010 à 20:01:37

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed