Johnny B.: Frage zu RegEx

Hallo geehrtes Forum,

seit langem komme ich mal wieder zum Programmieren und sogleich sind sie wieder da, die ungelösten Rätsel aus den Tiefen der RegEx-Maschine:

my $tel = '0 (1 77) / 987 65 43';  
$tel =~ s/(\d)[()\/\- ]+(\d)/$1$2/g;

Ergebnis: 01 779876543

Gewünschts Ergebnis: 01779876543

Ich kann mir denken, daß der RegEx die Ziffer 1 nach der Klammer bereits verbraucht hat und als nächstes ein Leerzeichen einliest, damit also nicht trifft.

Erreichen möchte ich, daß alle zwischen zwei Ziffern stehenden Zeichen ()/- und Leerzeichen gelöscht werden.

Ist mein Ansatz nicht zielführend, oder gibt es eine Möglichkeit, die RegEx-Maschine dazu zu bewegen, den letzten Treffer wieder zu vergessen?

Grübelnde Grüße
JOhnnY

  1. Erreichen möchte ich, daß alle zwischen zwei Ziffern stehenden Zeichen ()/- und Leerzeichen gelöscht werden.

    Dann erledige das in einem separaten Schritt.

    mfg Beat

    --
    Surftipp:
    Die NATO
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    Der Valigator leibt diese Fische
    1. Hallo Beat,

      Dann erledige das in einem separaten Schritt.

      so?

      my $tel = '0 (1 77) / 987 65 43';  
      $tel =~ s/(\d)[()\/\- ]+(\d)/$1$2/g;  
      $tel =~ s/(\d)[()\/\- ]+(\d)/$1$2/g;
      

      Führt zwar zum gewünschten Ergebnis, sieht ziemlich unelegant und auch fehleranfällig aus...

      Gruß, JOhnnY

  2. Hi,

    Hallo geehrtes Forum,

    seit langem komme ich mal wieder zum Programmieren und sogleich sind sie wieder da, die ungelösten Rätsel aus den Tiefen der RegEx-Maschine:

    my $tel = '0 (1 77) / 987 65 43';

    $tel =~ s/(\d)[()/- ]+(\d)/$1$2/g;

      
    Das macht:  
      
    Finde und merke eine Ziffer  
    Finde mind. 1 Zeichen aus ()/- und Leerzeichen  
    Finde und merke 1 Ziffer  
      
    Ersetze dieses durch das 1. und 2. gemerkte.  
      
    Wiederhole das ganze nach dem Ende der ersten Fundstelle.  
      
      
    Im ersten Durchgang wird  
    0 (1 gefunden und durch 01 ersetzt, der String sieht jetzt so aus: "01 77) / 987 65 43"  
      
    Im zweiten Durchgang wird ab dem Leerzeichen vor 77) weitergesucht.  
    Da das Leerzeichen keine Ziffer ist, wird ab der 7 probiert. Das ist zwar eine Ziffer, aber das folgende Zeichen keins aus der Zeichenklasse.  
    Also wird bei der 2. 7 versucht, zu matchen: das führt zum Erfolg: das ist eine Ziffer, danach diverse Zeichen aus der Zeichenklasse, gefolgt von einer Ziffer (der 9).  
    Das kann ersetzt werden, also sieht der String jetzt so aus: "01 77987 65 43"  
      
    Im dritten Durchgang wird ab der 8 gesucht. Da kein Zeichen aus der Klasse folgt, wird's mit der folgenden 7 probiert. Erfolg: das Leerzeichen ist in der Klasse, danach kommt eine Ziffer (die 6).  
    Ersetzung, String sieht jetzt so aus: "01 7798765 43"  
      
    Weiter geht's ab der 5. Die paßt, das folgende Leerzeichen auch, die 4 auch.  
    Ersetzung, String: "01 779876543".  
      
    Weiter geht's ab der 3. Die paßt, aber kein Zeichen mehr übrig ==> Fertig.  
      
      
      
    Ach ja, wenn es Dir nur darum geht, die Zeichen aus der Klasse aus dem String zu entfernen:  
    suche nur nach der Zeichenklasse und ersetze sie durch nichts.  
      
      
    cu,  
    Andreas
    
    -- 
    [Warum nennt sich Andreas hier MudGuard?](http://MudGuard.de/)  
    [O o ostern ...](http://ostereier.andreas-waechter.de/)  
      
    Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.  
    
    
    1. Hallo MudGuard,

      Ach ja, wenn es Dir nur darum geht, die Zeichen aus der Klasse aus dem String zu entfernen:
      suche nur nach der Zeichenklasse und ersetze sie durch nichts.

      Damit würde dann aber auch ein zwischen Buchstaben stehendes Leerzeichen gelöscht werden und das soll bestehen bleiben.

      Gruß, JOhnnY

      1. Hi,

        Ach ja, wenn es Dir nur darum geht, die Zeichen aus der Klasse aus dem String zu entfernen:
        suche nur nach der Zeichenklasse und ersetze sie durch nichts.

        Damit würde dann aber auch ein zwischen Buchstaben stehendes Leerzeichen gelöscht werden und das soll bestehen bleiben.

        a) Was denn für Buchstaben - ich dachte dir geht es um Ziffern?

        b) Zitat du:

        Gewünschts Ergebnis: 01779876543

        • wo sind denn jetzt da die Leerzeichen?

        Bitte drücke dich präzise(r) aus - und zwar gleich von Anfang an.

        MfG ChrisB

        --
        RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
        1. Hallo ChrisB,

          Bitte drücke dich präzise(r) aus - und zwar gleich von Anfang an.

          Ich habe in meinem Beispiel keine Buchstaben verwendet, daß war leider zweideutig.

          Also nochmal präzise(r):

          my $tel = '0 (1 77) / 560 11 26 abc def (gh)';  
          $tel =~ s/(\d)[()\/\- ]+(\d)/$1$2/g;
          

          Ergebnis: 01 775601126 abc def (gh)
          gewünschtes Ergebnis: 01775601126 abc def (gh)

          Erreichen möchte ich, daß alle zwischen zwei Ziffern stehenden Zeichen ()/- und Leerzeichen gelöscht werden.

          Gruß, JOhnnY

          1. Bounjoun Johnny B.,

            Erreichen möchte ich, daß alle zwischen zwei Ziffern stehenden Zeichen ()/- und Leerzeichen gelöscht werden.

            Dann zieh' Dir die Antwort von CPAN 'rein. Es muss nicht immer RegExp sein.

            Adiou.

            1. Hallo Jean-Max,

              Erreichen möchte ich, daß alle zwischen zwei Ziffern stehenden Zeichen ()/- und Leerzeichen gelöscht werden.

              Dann zieh' Dir die Antwort von CPAN 'rein. Es muss nicht immer RegExp sein.

              Den Unterschied von von tr zu s habe ich noch nicht geblickt. Tatsächlich sehe ich nicht, was tr kann, was s nicht kann; oder wann ich es einsetzen sollte oder warum ich dafür keinen RegExp nehmen sollte. In der Tat habe ich tr bisher noch nie verwendet.

              Jedenfalls löscht CPAN's Vorschlag ja ALLE ()/-, auch die zwischen zwei Nicht-Ziffern befindlichen.

              Gruß, JOhnnY

              1. Bounjoun Johnny B.,

                Den Unterschied von von tr zu s habe ich noch nicht geblickt.

                TR steht für »Transliteration« während S für »substitution« steht.

                Wie das intern funktioniert, kann ich Dir leider nicht sagen. So ein Profi bin ich auch nicht. Ob die Transliteration (früher auch mit y///) die RegExp-Maschine anwirft, weiß ich nicht, sieht aber ob der Syntax so aus.

                Zumindest in Sachen RegExp ist m = match (da wird nur getestet, ob der Audruck  eben zutrifft), und s = substitution = Ersetzung (da wird der Ausdruck getestet und bei Erfolg ersetzt).

                Jedenfalls löscht CPAN's Vorschlag ja ALLE ()/-, auch die zwischen zwei Nicht-Ziffern befindlichen.

                Und? Suchtest Du nicht eben nach einer -wie-auch-immer-Lösung für Telefonnummern?

                Adiou.

          2. Tach auch.

            Ergebnis: 01 775601126 abc def (gh)
            gewünschtes Ergebnis: 01775601126 abc def (gh)

            MudGuard hat dir bereits gesagt, wie der RegEx ausgewertet wird.
            Um dein Problem zu lösen, füge einfach noch ein [()/-]* am Ende der Suchfolge an und gehe MudGuards Text dann nochmal durch, ob dann alles stimmt.

            Bis die Tage,
            Matti

            1. Hallo Matti,

              Um dein Problem zu lösen, füge einfach noch ein [()/-]* am Ende der Suchfolge an und gehe MudGuards Text dann nochmal durch, ob dann alles stimmt.

              oh mann... Einfach einen Schritt weiter denken. <klatsch_an_kopf>

              Danke!

              Gruß, JOhnnY

              1. oh mann... Einfach einen Schritt weiter denken. <klatsch_an_kopf>

                wobei diese Lösung unsauber ist: 1/2/a wird zu 12a. Damit wird ein Zeichen gelöscht, welches nicht zwischen zwei Ziffern steht.

      2. Hi,

        Ach ja, wenn es Dir nur darum geht, die Zeichen aus der Klasse aus dem String zu entfernen:
        suche nur nach der Zeichenklasse und ersetze sie durch nichts.

        Damit würde dann aber auch ein zwischen Buchstaben stehendes Leerzeichen gelöscht werden und das soll bestehen bleiben.

        Sowohl Dein Beispielstring als auch der benutzte Variablenname $tel legten nahe, daß es sich um Telefonnummern handelt, also keine Buchstaben vorhanden sind.

        Dann suche nach der Zeichenklasse (mit +) und setze vorher/nachher einen positive lookbehind/lookahead auf eine Ziffer.

        cu,
        Andreas

        --
        Warum nennt sich Andreas hier MudGuard?
        O o ostern ...
        Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.
        1. Hallo Andreas,

          Dann suche nach der Zeichenklasse (mit +) und setze vorher/nachher einen positive lookbehind/lookahead auf eine Ziffer.

          Aaaaaaaha. Genau sowas hatte ich gesucht: RegEx-Treffer, die nicht mitzählen. Cool! Die saubere Lösung ist:

          $tel =~ s/(?<=\d)[()\/\- ]+(?=\d)//g;

          Muchas Gracias
          JOhnnY

  3. Wenn ich auf das gewüschte Ergebis schaue, sieht es für mich so aus, als wolltest du einfach alle Leerzeichen, Klammern, Schrägstriche entfernen. Machst du dir das Programmiererleben unnötig schwer? Falls ja, denn nimm tr:

      
    my $tel = '0 (1 77) / 987 65 43';  
    $tel =~ tr{()/ }{}d;  
    $tel; # 01779876543