theozh: Perl Rechnung in Regex

Hallo Perl-Spezialisten,

in einem Text habe ich viele Zeitangaben in spitzen Klammern in Millisekunden, z.B. '<123456789>'. Diese wollte ich alle in Stunden:Minuten:Sekunden.Millisekunden, d.h. z.B. '(34:17:36.789)' umwandeln. Dabei wäre

xxx = Millisekunden

hh = (int(xxx/3600000))

mm = int((xxx - hh * 3600000)/60000)

ss = int((xxx - hh * 3600000 - mm * 60000)/60000)

nnn = xxx % 1000

Wenn man das nun alles ineinander einsetzt, ergibt sich ein sehr langer Ausdruck. Der Einfachheit und Übersicht halber im Folgenden mal nur auf die Extraktion von Stunden und Millisekunden reduziert. Ich hoffte, dass der folgende oder so ähnliche Code mit den Flags 'gse' die Ersetzung erledigen würde.

 my $Text =~ s!<(\d+)>!\(int($1/3600000):mm:ss\.$1%1000\)!gse

Das funktioniert leider so nicht. Sobald ich $1 mehrfach verwende gibt's eine Fehlermeldung.

Wer kann mir auf die Sprünge helfen? Danke, Theo.

akzeptierte Antworten

  1. Moin,

    ich bin zwar kein Perl-Spezialist - im Gegenteil, ich habe von Perl fast keine Ahnung.

    in einem Text habe ich viele Zeitangaben in spitzen Klammern in Millisekunden, z.B. '<123456789>'. Diese wollte ich alle in Stunden:Minuten:Sekunden.Millisekunden, d.h. z.B. '(34:17:36.789)' umwandeln.

    Aber dass man eine komplizierte Rechnung nicht in einem Regex machen kann, ist auch mir klar. Regex arbeitet auf Strings, da wird nix berechnet. Regex sind nicht für jedes Problem geeignet.

    Dabei wäre

    xxx = Millisekunden

    hh = (int(xxx/3600000))

    mm = int((xxx - hh * 3600000)/60000)

    ss = int((xxx - hh * 3600000 - mm * 60000)/60000)

    nnn = xxx % 1000

    Ich würd's vom Rechenweg her andersrum und schrittweise machen, dann wird's übersichtlicher. Etwa so:

    nnn = xxx % 1000;   // Millisekunden
    xxx /= 1000;
    ss  = xxx % 60;     // Sekunden
    xxx /=60;
    mm  = xxx % 60;     // Minuten
    xxx /=60;
    hh  = xxx;          // und die Stunden bleiben übrig.
    

    Jetzt muss man das nur noch bei der Ausgabe mit führenden Nullen formatieren.

    So long,
     Martin

    --
    Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
    - Douglas Adams, The Hitchhiker's Guide To The Galaxy
  2. Wer kann mir auf die Sprünge helfen?

    "callback"

    $x = "this is a test";
    $x =~ s/(test)/reverse($1)/eg;
    print $x;
    
    //this is a tset
    

    schreib Dir also selbst eine Funktion (das Skript nutzt reverse()) welche die Berechnung ausführt und nutze diese.

    1. Danke für Eure rasche Rückmeldungen.

      @"DerMartin", ja, umgekehrt ist es sicher eleganter, doch ich dachte, ich müsste das als geschlossenen Ausdruck in der Regex einbinden. Aber ja, man kann einfache Rechnungen in einer Regex erledigen.

      Wenn es allerdings komplexer wird hilft wohl nur eine eigene Funktion. Vielen Dank @"Google weiß alles" für den Tipp!

      Folgender Code erfüllt meinen Zweck.

       my $Text =~ s!<(\d+?)>!&ConvertMilliseconds($1)!gse;
      
      sub ConvertMilliseconds {
        my $xxx = shift;
      
        my $nnn = $xxx % 1000;
        $xxx /= 1000;
        my $ss  = $xxx % 60;
        $xxx /=60;
        my $mm  = $xxx % 60;
        $xxx /=60;
        my $hh  = $xxx;
        
        return sprintf("(%02d:%02d:%02d.%03d)",$hh,$mm,$ss,$nnn);
      };