SorgenKindMech: / RegEx Telefonnummern

Huhu liebes Forum,

ich bin gerade dabei eine kleine funktion zu basteln, die aus verschiedenen texten rufnummern filern und ersetzen soll

ich hab da mal ein anfang gemacht und mich mit regex rumgeschlagen ... holla die waldfee ... wer es kann liebt es bestimmt, aber ich hasse es ;)

ich bin mir durchaus bewusst, dass ich mit meinem regex vielleicht mehr treffe als ich will, aber das ist nicht schlimm, ein bisschen schwund ist immer *g*

aufbau wie folgt:

Ländervorwahl (Unterstrich=Leerzeichen):
[+][0-9]{2,4}[ |/|.|-]? +49_
|00[0-9]{2,4}[ |/|.|-]? 0049_
|0 0
|(0 (0
Ortsvorwahl:
[1-9][0-9]{1,4}[)]?[ |/|.|-]? 123 (nicht mit 0 beginnend) vielleicht eine schließende klammer und vielleicht noch ein trennzeichen
restliche rufnummer:
[- 0-9]+ beliebig viele zahlen, auch leerzeichen und bindestriche dürfen enthalten sein

daraus ergibt sich folgender beispielhafter regex:

preg_match_all("~([+][0-9]{2,4}[ |/|\.|\-]?|00[0-9]{2,4}[ |/|\.|\-]?|0|\(0)([0-9]{2,5}[\)]?[ |/|\.|\-]?)([\- 0-9]+)~m",$notiz['msg'],$telefonnummern);

soweit funktioniert er ja ganz gut, es seien folgende teststrings gegeben:

0123 456 78 9
0123-456 78 9
0123/456789
+49 123 45 67 89 asdasd
0049 123 456789
0049/123/456789
(030) 123 456
0049 (030) 123 45678

alle funktionieren super, aber ausgerechnet der letze geht total in die hose
soweit ich gelesen habe wird der ausdruck von links nach rechts interpretiert, jedoch nimmt er mit die zweite (!) 0, dann das 49 und dann das leerzeichen als einzelnes .... warum? im ersten teilausdruck trifft doch das zweite pattern (heißt das so?) voll zu

kann mir das jemand erklären?

btw: für optimierungsvorschläge die NICHT die übersichtlichkeit für anfänger flöten lassen gehen bin ich auch dankbar ;)

  1. Tach!

    ich bin gerade dabei eine kleine funktion zu basteln, die aus verschiedenen texten rufnummern filern und ersetzen soll
    ich hab da mal ein anfang gemacht und mich mit regex rumgeschlagen ... holla die waldfee ... wer es kann liebt es bestimmt, aber ich hasse es ;)

    Du kannst es dir leichter machen, wenn du nicht einen Riesenausdruck zu bauen versuchst, sondern für jedes Muster einen eigenen Ausdruck erstellst. Diese lässt du nacheinander auf die Nummer los und schaust, ob irgendeiner passt.

    Ländervorwahl

    _Landes_vorwahl, es ist ja die eines Landes, nicht mehrerer (mit Ausnahme von Zone 7).

    [+][0-9]{2,4}[ |/|.|-]? +49_

    In []-Klammern steht eine Zeichenklasse. In der gelten andere Regeln für Sonderzeichenbedeutungen. Das | ist dort nur ein normales Zeichen, du scheinst es jedoch als Oder verwenden zu wollen. Es ist auch nicht erforderlich, Zeichen außer ] zu maskieren, schadet aber auch nicht. Allerdings hat das - als Bereichskennzeichnung eine Bedeutung - oder auch nicht, je nachdem wo es steht. Am Anfang und am Ende steht es für sich selbst, mittendrin nur mit Maskierung.

    |00[0-9]{2,4}[ |/|.|-]? 0049_

    Hier wäre 00[1-9]\d{1,3} richtiger, weil die erste Ziffer nach der IVAZ[*] keine 0 sein kann. Und \d steht für Ziffern, kann also [0-9] ersetzen.

    preg_match_all("~([+][0-9]{2,4}[ |/|\.|\-]?|00[0-9]{2,4}[ |/|\.|\-]?|0|\(0)([0-9]{2,5}[\)]?[ |/|\.|\-]?)([\- 0-9]+)~m",$notiz['msg'],$telefonnummern);

    Selbst wenn ich den Ausdruck um überflüssige Zeichen erleichtere

    ~(+\d{2,4}[ /.-]?|00\d{2,4}[ /.-]?|0|(0)(\d{2,5})?[ /.-]?)([-\d]+)~m

    ist er mir noch zu komplex, um ihn im Moment vollständig nachzuvollziehen.

    0049 (030) 123 45678

    Das ist eine sehr ungünstige falsche Schreibweise. Abgesehen davon, dass zwar viele Länder die 00 als IVAZ haben, aber eben nicht alle, ist es selbst für die 00-Länder nicht eindeutig, was der Teil nach der Landesvorwahl zu bedeuten hat. Die Klammern deuten Optionalität an, aber vom Ausland aus benötigt man die 30, nicht aber die führende 0 - in diesem Fall. Das ist insofern missverständlich, als es Länder gibt, bei denen die 0 mitgewählt werden muss. Und um das Kraut noch fett zu machen, gibt es in Italien beispielsweise Ortsnetzkennzahlen mit und ohne 0. In Tschechien ist die 0 auch nicht ohne Bedeutung.

    +49 (0)30 123 45678

    wäre eine noch einigermaßen akzeptable und verbreitete Schreibweise, weil die 0 aus dem Inland mitgewählt werden muss, aus dem Ausland aber nicht. Einfach zu verstehen ist es trotzdem nicht. Vermutlich aber hast du hier keinen Spielraum und musst den Mist verarbeiten, den du bekommst. Herzliches Beileid.

    kann mir das jemand erklären?

    Zum eigentlichen Problem kann ich dir grad nur den eingangs erwähnten Tipp geben.

    btw: für optimierungsvorschläge die NICHT die übersichtlichkeit für anfänger flöten lassen gehen bin ich auch dankbar ;)

    Definiere Übersichtlichkeit.

    [*] IVAZ = internationale Verkehrsausscheidungsziffer (keine offizielle Abkürzung)

    dedlfix.

    1. Hallo,

      Ländervorwahl
      _Landes_vorwahl, es ist ja die eines Landes, nicht mehrerer (mit Ausnahme von Zone 7).

      und 1: Die Vorwahl +1 gilt auch für USA und Kanada gemeinsam. Aber das nur nebenbei.

      Ciao,
       Martin

      --
      Wie kann es sein, dass ich von 100 Gramm Schokolade zwei Kilo zunehme?
      Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
      1. Tach!

        Ländervorwahl
        _Landes_vorwahl, es ist ja die eines Landes, nicht mehrerer (mit Ausnahme von Zone 7).
        und 1: Die Vorwahl +1 gilt auch für USA und Kanada gemeinsam. Aber das nur nebenbei.

        Gut, der NANP läuft sowieso per Design außer Konkurrenz. Da gibts ja auch noch diverse Inseln, die sich diese 1 quasi ebenfalls teilen.

        dedlfix.

    2. Tach!

      ich bin gerade dabei eine kleine funktion zu basteln, die aus verschiedenen texten rufnummern filern und ersetzen soll
      ich hab da mal ein anfang gemacht und mich mit regex rumgeschlagen ... holla die waldfee ... wer es kann liebt es bestimmt, aber ich hasse es ;)

      Du kannst es dir leichter machen, wenn du nicht einen Riesenausdruck zu bauen versuchst, sondern für jedes Muster einen eigenen Ausdruck erstellst. Diese lässt du nacheinander auf die Nummer los und schaust, ob irgendeiner passt.

      hm, das habe ich noch nicht getestet ...
      das problem ist ja, dass es ein text unbekannter länge ist, beispielsweise eine notiz ala:

      hallo frau müller
      der herr frank (0123 45678900) hat versucht den herrn meier (02545/4654654) zu erreichen, leider erfolglos! plan 08/15 muss unbedingt fertig werden!

      nur so als beispiel, und da ich nicht unnötigen "müll" treffen wollte, hab ich gedacht, muss ich sowieso in einem machen

      Ländervorwahl

      _Landes_vorwahl, es ist ja die eines Landes, nicht mehrerer (mit Ausnahme von Zone 7).

      [+][0-9]{2,4}[ |/|.|-]? +49_

      In []-Klammern steht eine Zeichenklasse. [...]

      verstehe, danke, das macht es zumindest schonmal ein wenig übersichtlicher ;)

      |00[0-9]{2,4}[ |/|.|-]? 0049_

      Hier wäre 00[1-9]\d{1,3} richtiger, weil die erste Ziffer nach der IVAZ[*] keine 0 sein kann. Und \d steht für Ziffern, kann also [0-9] ersetzen.

      das dachte ich mir auch, hab es dann aber zum wohle der übersichtlichkeit (haha) übergangen ;)

      preg_match_all("~([+][0-9]{2,4}[ |/|\.|\-]?|00[0-9]{2,4}[ |/|\.|\-]?|0|\(0)([0-9]{2,5}[\)]?[ |/|\.|\-]?)([\- 0-9]+)~m",$notiz['msg'],$telefonnummern);

      Selbst wenn ich den Ausdruck um überflüssige Zeichen erleichtere

      ~(+\d{2,4}[ /.-]?|00\d{2,4}[ /.-]?|0|(0)(\d{2,5})?[ /.-]?)([-\d]+)~m

      ist er mir noch zu komplex, um ihn im Moment vollständig nachzuvollziehen.

      wäre eine noch einigermaßen akzeptable und verbreitete Schreibweise, weil die 0 aus dem Inland mitgewählt werden muss, aus dem Ausland aber nicht. Einfach zu verstehen ist es trotzdem nicht. Vermutlich aber hast du hier keinen Spielraum und musst den Mist verarbeiten, den du bekommst. Herzliches Beileid.

      danke, und ja, ich muss den mist verarbeiten ...
      leider habe ich auf die daten die da rein kommen nicht wirklich zugriff oder einflussmöglichkeit, um diese direkt bei der eingabe ein wenig zu validieren

      btw: für optimierungsvorschläge die NICHT die übersichtlichkeit für anfänger flöten lassen gehen bin ich auch dankbar ;)

      Definiere Übersichtlichkeit.

      Übersichtlich ist es dahingehend für mich, dass ich 3 abschnitte habe, in denen ich jeweils verschiedene möglichkeiten abklappern kann ... also für mich ist es so verständlicher, als ganz klein gemacht

      aber dennoch danke erstmal bis hierhin, ein stück schlauer bin ich auf jeden fall ;)

      1. Tach!

        das problem ist ja, dass es ein text unbekannter länge ist, beispielsweise eine notiz ala:
        hallo frau müller
        der herr frank (0123 45678900) hat versucht den herrn meier (02545/4654654) zu erreichen, leider erfolglos! plan 08/15 muss unbedingt fertig werden!
        nur so als beispiel, und da ich nicht unnötigen "müll" treffen wollte, hab ich gedacht, muss ich sowieso in einem machen

        Ob du den Müll nun mit keinem der Einzelschritte triffst oder in einem großen Ausdruck ausklammerst, sollte am Ergebnis nichts ändern.

        leider habe ich auf die daten die da rein kommen nicht wirklich zugriff oder einflussmöglichkeit, um diese direkt bei der eingabe ein wenig zu validieren

        Da können dir dann aber auch Schreibweisen durchrutschen, die du nicht berücksichtigt hast. Das weißt du sicherlich, aber wenn du dann mal eine hinzufügen willst, musst du deinen Riesenausdruck zum einen wieder verstehen - und auch dein Gehirn wird gut im Verdrängen sein - und zum anderen so erweitern, dass keines der anderen Muster beschädigt wird.

        dedlfix.

  2. Hallo SorgenKindMech,

    ich bin mir durchaus bewusst, dass ich mit meinem regex vielleicht mehr treffe als ich will, aber das ist nicht schlimm, ein bisschen schwund ist immer *g*

    Ich würde jetzt nicht unbedingt probieren mit regulären Ausdrücken Telefonnummern auf deren Korrektheit zu verifizieren, da der Input ja auch von Menschen kommt und - wie du ja schreibst - nicht bei der Eingabe überprüft wurde.

    Möchtest du lange Zahlen aus einem Text filtern der mit hoher Wahrscheinlichkeit Telefonnummern enthält bzw falls er längere Zahlen enthält sind diese Zahlen mit hoher Wahrscheinlichkeit Telefonnummern.

    Da würd ich etwas einfaches hinrotzen und dann gegebenenfalls anpassen:
    '~(?[0+]?\d+[-\d/ ()]{5,}\d+)?~'

    Es kann mit einer öffnenden Klammer starten
    danach kann ein + oder eine 0 kommen
    Es muss eine Zahl folgen, gefolgt von mindestens 5 Zeichen, die einem Bindestrich, einer Zahl, einem Slash, einem Leerzeichen, oder einer runden Klammer entsprechen.
    Abschließend muß eine Zahl kommen
    Danach kann noch eine schließende Klammer folgen.

    Viele Grüße,
    Jonny 5

    1. Hallo nochmal,

      Es muss eine Zahl folgen ...
      Abschließend muß eine Zahl kommen

      Kleine Korrektur, so hab ichs gemeint:
      '~(?[0+]?\d[-\d/ ()]{5,}\d)?~'

      Viele Grüße,
      Jonny 5