Forum Programmation.perl parser un gros fichier

Posté par  (site web personnel) .
Étiquettes : aucune
-1
15
oct.
2004
J'ai un fichier binaire qui peut faire plusieurs Go à parser.

Je le lis avec read par bloc. Mon problème est que un motif peut être à cheval sur 2 blocs. Je penssais utiliser une sorte de fifo de taille double du buffer pour faire ça. Mais je me demande si il n'y a pas de manière plus "idiomatique".
  • # meuh

    Posté par  (site web personnel) . Évalué à 2.

    idiomatique ?
    • [^] # Re: meuh

      Posté par  (site web personnel) . Évalué à 1.

      ben une manière plus perlienne, quoi.

      Le type de code que l'on retrouverait dans un programme d'un bon codeur perl.

      J'ai un peu peur en fait que lancer une regex sur une fifo de taille double soit un peu lent :/

      "La première sécurité est la liberté"

      • [^] # Re: meuh

        Posté par  (site web personnel) . Évalué à 3.

        bah. moi je ferais :

        open F, '</tmp/track01.cdda.wav' or die "open: $!\n";

        my ($buf, $prev);
        while (1) {
            my $ret = read F, $buf, 4096;
            if (!defined($ret)) {
                die "read: $!\n"
            } elsif (!$ret) {
                last;
            } else {
                if ("$prev$buf" =~ /(gc\w\w)/) {
                    print "match: $1\n";
                }
                $prev = $buf;
            }
        }

        mais y'a sûrement pire.
        • [^] # Re: meuh

          Posté par  (site web personnel) . Évalué à 1.

          Je fais :
          my $bufferbin;
          my $oldbufferbin = "";
          while (read FICHIER, $bufferbin, 4*1024){
              my $fifo = $oldbufferbin.$bufferbin;    
              while ($fifo =~ /(\x1A\xCF\xFC\x1D.{2000,2100})\x1A\xCF\xFC\x1D/g){
          	my $cadu = $1;
                  blablabla ....
              }
              $oldbufferbin = $bufferbin;
          }
          
          cela ressemble beaucoup à ton code. j'ai un problème par contre sur le while (/../g), j'ai un début de trame marqué par le code. Donc la fin de la trame est donné par le début de la trame suivante. Mais si j'utilise la regex d'en haut, la boucle suivante ne va pas matcher le début de la trame (qui la fin de la précédente). Il faudrait lui dire de revenir en arrière. Mais je n'ai pas encore trouvé comment.

          "La première sécurité est la liberté"

          • [^] # Re: meuh

            Posté par  (site web personnel) . Évalué à 1.

            En fait, ça marche (presque) avec :

            /(\x1A\xCF\xFC\x1D(.|\x00){2000,2100})(?=\x1A\xCF\xFC\x1D)/

            Le truc c'est (?=...) qui n'est pas pris en compte dans le déplacement.

            "La première sécurité est la liberté"

            • [^] # Re: meuh

              Posté par  (site web personnel) . Évalué à 1.

              bon en fait cela ne marche pas du tout.

              J'ai l'impression qu'il match toujours la même trame :(

              il doit y avoir un soucis avec la définition du "while (//g)"

              "La première sécurité est la liberté"

  • # Une solution...

    Posté par  . Évalué à 3.

    Un truc comme ca ?


    my ($buffer, $chunk);
    my $SEPARATOR = 'X'; # C'est ton séparateur de motifs

    while (read F, $chunk, 4096)
    {
    die "Read problem" if not defined $chunk;
    last if not $chunk;
    $buffer .= $chunk;
    if ($buffer =~ s/^([^SEPARATOR]*)$SEPARATOR//)
    {
    ProcessOneFrame ($1);
    }
    }

    die "Incomplete Frame ??" if $buffer;


    P.S. il faut faire le même genre de choses pour les paquets IP fragmentés, ils peuvent arriver en plusieurs fois, et il faut donc "recoller les morceaux"

    P.P.S code pas testé
    • [^] # Re: Une solution...

      Posté par  (site web personnel) . Évalué à 1.

      " $buffer .= $chunk;" <- pas bon ça !

      à la fin buffer fait une taille énorme.

      j'ai toujours mon pb de relecture pour les 2ième passes :/

      "La première sécurité est la liberté"

      • [^] # Re: Une solution...

        Posté par  . Évalué à 2.

        Oui, mais il se vide chaque fois qu'il peut :

        $buffer =~ s/^([^SEPARATOR]*)$SEPARATOR//

        (qu'on pourrait d'ailleurs avantageusement remplacer par :

        while ($buffer =~ s/^([^SEPARATOR]*)$SEPARATOR//)
        {
        ProcessOneFrame ($1);
        }
        • [^] # Re: Une solution...

          Posté par  (site web personnel) . Évalué à 1.

          à oui, j'avais pas vu.

          c'est pas plutôt : "s/^([^SEPARATOR].*)$SEPARATOR//)" et c'est vrai que cela à l'avantage de bien réduire la taille buffer et d'aller plus vite j'imagine.

          "La première sécurité est la liberté"

    • [^] # Re: Une solution...

      Posté par  (site web personnel) . Évalué à 1.

      Pourrais-tu détailler la regexp que tu utilises, pourquoi une variable pourquoi 2x "^" pourquoi les '[]' etc..

      "La première sécurité est la liberté"

      • [^] # Re: Une solution...

        Posté par  . Évalué à 3.

        Oulala, vaste question...

        Le premier ^ spécifie "Début de chaine"

        Les [] veulent dire "Un des caractères parmi... et le ^ dans les [] effectue une négation, donc "aucun des caractères parmi".

        De façons plus générale, il est difficile (et inutile) d'expliquer ce que sont les regexp et comment elles fonctionnent dans un forum... Plutôt te renvoyer vers quelques sources d'information :

        - perldoc perlrequick ou perldoc perlretut ou perldoc perlre ou encore perldoc perlreref (il faut avoir installé le package de documentation Perl qui va bien)
        - l'excellent livre consacré aux regexp de chez O'Reilly http://www.oreilly.com/catalog/regex/(...)
        - google
        - et le sympatique Vrex qui a tout pour plaire à un débutant : http://page.sourceforge.net/vrex.html(...)

        Bon courage ! (et comment as-tu pu vivre sans elles ?)
        • [^] # Re: Une solution...

          Posté par  (site web personnel) . Évalué à 2.

          Je connais les regexp, je ne savais pas que "^" signifiait une négation, je croyais que cela voulais dire une nouvelle fois "début de fichier". Ce qui m'embrouillais sur le reste

          "La première sécurité est la liberté"

          • [^] # Re: Une solution...

            Posté par  (site web personnel) . Évalué à 1.

            Bon, j'ai eu quelques soucis en plus.

            Mon délimiteur fait plusieurs caractère de long donc le "truc" [^abc] ne marche pas. Ensuite, je parse du binaire et "." ne peut pas prendre certaine valeur notement "\n", il faut rajouter /s pour cela.

            Donc ma regexp est devenu :

            s/(\x1a\xcf\xfc\x1d.{2000,2100})((?=\x1a\xcf\xfc\x1d)|$)//s

            (?=) pour la présence du délimiteur à la fin
            /s pour ne pas se faire avoir avec '.'

            vala merci pour l'aide !

            "La première sécurité est la liberté"

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.