kaepten: Funktion "pack()"

Hallo zusammen

Ich besitze leider nur ganz dürftge Dokumentationen über Perl. Leider kann ich aber mit der folgenden Code-Zeile (kopiert aus einem GästebuchScript) nichts anfangen. Durch was wird hier ersetzt? Ich kenne das pack("C"... nicht. Was bedeuted das?

$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

Wer kann mir ein wenig auf die Sprünge helfen?
Mit Dank zum Voraus!
cheers
kaepten

  1. Hi!

    Ich besitze leider nur ganz dürftge Dokumentationen über Perl. Leider kann ich aber mit der folgenden Code-Zeile (kopiert aus einem GästebuchScript) nichts anfangen. Durch was wird hier ersetzt? Ich kenne das pack("C"... nicht. Was bedeuted das?

    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

    Ganz einfach:
    Bei einem CGI-Aufruf werden Sonderzeichen durch Ihren Hexadezimalwert repräsentiert. Dies geht auch für nicht-Sonderzeichen. Z.B ist space der 32te ASCII Wert also in hex: 20. Die Repräsentation wird durch ein % angezeigt.

    Um nun einen solchen String in Perl vernünftig verarbeiten zu können. Müßen die Hex-Repräsentationen in "echte" Character (dafür das 'C') gewandelt werden. Dazu werden sämtliche %xx Stellen (mit x = 0-9 oder a-f) ersetzt. xx wird gewandelt in eine Zahl durch hex($1) und hierzu wird der entsprechende Character-Wert erzeugt und eigesetzt.

    Jörk

    1. Hi!

      $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

      Ich benutze uebrigens immer den Ausdruck
          s/%([0-9A-Fa-f]{2})/chr(hex($1))/ge;
      Funzt auch sehr gut, und vor allem weiss ich, wie chr() und hex() funktionieren. pack() dagegen habe ich bis heute noch nicht so richtig verstanden. Aber kommt vielleicht noch. *g*

      Vielleicht koennte man ja auch \w statt [a-fA-F0-9] verwenden. \w beinhaltet lediglich noch zusaetzlich den Underscore _, und wenn die URL den Regeln folgt, kommt dieser niemals nach einem %-Zeichen.

      Calocybe

      1. Hallo!

        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

        Ich benutze uebrigens immer den Ausdruck
            s/%([0-9A-Fa-f]{2})/chr(hex($1))/ge;

        bei mir isses s/%([0-9a-f]{2})/pack('H2', $1)/egi;
        ;-) habe hier einen zweistelligen HexWert, der in ein Byte gepackt werden soll ...

        Vielleicht koennte man ja auch \w statt [a-fA-F0-9] verwenden. \w beinhaltet lediglich noch zusaetzlich den Underscore _, und wenn die URL den Regeln folgt, kommt dieser niemals nach einem %-Zeichen.

        sogesehen schon - Du hast aber noch den ganzen Rest der Buchstabe-Suppe vergessen ;-)

        ciao,
           Jörk

        1. Hi nochmal!

          sogesehen schon - Du hast aber noch den ganzen Rest der Buchstabe-Suppe vergessen ;-)

          Oh, Mist. Ok, dann vergessen wir das mit dem \w besser wieder. Schliesslich garantiert keiner, dass irgendein User nicht mal eine nicht regelgerechte URL eintippt.

          Calocybe

    2. Hallo Jörk, hallo kaepten,

      Um nun einen solchen String in Perl vernünftig verarbeiten zu können. Müßen die Hex-Repräsentationen in "echte" Character (dafür das 'C') gewandelt werden. Dazu werden

      ich habe noch was zur Verdeutlichung, was wohl in Deinem (keapten) Gästebuch so ähnlich stehen mag:

      read (STDIN,$eingabe,$ENV{'CONTENT_LENGTH'});
      @eingabe=split(/&/,$eingabe);

      foreach $i (0..$#eingabe)
      {
        $eingabe[$i]=~ s/+/ /g;
        $eingabe[$i]=~ s/%(..)/pack("c",hex($1))/ge;
        ($feldname,$wert)=split(/=/,$eingabe[$i],2);
        $eingabe{$feldname}=$wert;
      }

      Damit wird aus dem per post (html-formular) gesendeten Datenstrom wieder die Zugehörigkeit der Werte zu den einzelnen Variablen restauriert, d.h. der Wert <value>, der im <input>-Feld mit dem Namen <name> eingelesen wurde, läßt sich dann hier so wieder auslesen und weiterverarbeiten:

      Bsp. aus dem HTML-Code:
      <input type="text" name="pass1" size=10>

      Verarbeitung unter Perl:

      $wert=$eingabe{'pass1'};

      Alles Gute,
      Reiner

      $eingabe

  2. Hi Kaepten

    Mit den pack/unpack-Funktionen habe ich gerade kürzlich viele mühsame Stunden verbracht (grumml).

    Das Hauptproblem liegt dabei bei Perl in der Repräsentation von Zahlen im Speicher:

    Zum Beispiel die Zahl 128 wird _nicht_ als ein Byte mit der Bitfolge '10000000' im Speicher abgelegt, sondern als 3-Byte-Skalar mit der Bitfolge '00110001 00110010 00111000', wobei jedes Byte dem Ascii-Wert der jeweiligen Zahl entspricht (Zahl 1 = Ascii 49, Zahl 2 = Ascii 50, ...).

    Für irgendwelche Zahlen- oder Bit-Operationen werden die Sklare (sofern möglich) implizit wieder in das richtige Format umgewandelt. Darum stört diese Phänomen in der Regel nicht.

    Bekommt man jedoch aus einer anderen Datenquelle einen binären Datenstrom, der die Zahl 128 als '10000000' enthält, muss dieser Wert mit der unpack-Funktion in ein Perl-Skalar umgewandelt werden. Dies geschieht mit der Funktion:

    $PerlSkalar = unpack("C", $binärWert);

    $binärWert enthält die binäre Repräsentation eines Wertes (z.B. '10000000')
      $PerlSkalar enthält danach den Skalar mit der Zahl 128 (in drei Bytes)

    Die Pack-Funktion funktioniert genau andersrum, dort wird ein Perl-Skalar in eine binäre (oder andere) Repräsentation umgesetzt.

    Die Art der Repräsentation hängt vom Template in der pack-Funktion ab (das erste Funktionsargument). Dabei bedeutet das "C" das ein unsigned-char (wie in der Programmiersprache C) zurückgegeben werden soll, was einem 8-Bit-Wert ohne Vorzeichen entspricht (z.B.'10000000' für 128). Es gibt noch viele weitere Templates, diese können in der Perldokumentation im Kapitel perlfunc unter pack() nachgeschlagen werden.

    Entsprechend wird in Deinem Beispiel ein hexadezimaler Datenstrom (nach Perl-Notation) 2-zeichenweise in ein binären Bytestrom umgesetzt (z.B. wird 'AF' zum Byte (unsigned-char) '10101111' ).

    Grüsse

    Tom