Boris: REGEX zum matchen von Grad&Bogenminuten

Hallo!

Ich versuche grade eine Geoposition in ihre bestandteile zu zerlegen.
Beispiele:

9°55'55.71"O
9°55'55.71" ö.L.
9°55.95'E
usw.

dabei komme ich mit meinen beschränkten wissen auf diese REGEX:

$anzahl = preg_match_all("/-?\d[.,]?\d*[°'\"]?\s?[NEOWSnoswö]?/",$string,$matches);

danach floatval()e ich die matches.

Nun zum Problem:
bei dem obigen beispiel 9°55'55.71"O matcht php 9,55,55 und leider auch 71. Irgendwie kann ich nicht sagen, dass 55.71 eine fliesskommazahl ist. Sollte es statt meiner (nicht so eleganten \d[.,]?\d lösung eine \dfloat lösung geben, wird das matching auch mit 9°55'55,71"O gehen?

fragen über fragen,
bo

  1. Ich versuche grade eine Geoposition in ihre bestandteile zu zerlegen.

    Ja dann tu das. Deine Rex ist eher das Gegenteil dessen.

    $anzahl = preg_match_all("/-?\d[.,]?\d*[°'\"]?\s?[NEOWSnoswö]?/",$string,$matches);

    Alles zusammenflanschen wird nix.

    mfg Beat;

    --
    Woran ich arbeite:
    X-Torah
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
  2. Hi,

    Ich versuche grade eine Geoposition in ihre bestandteile zu zerlegen.

    Wie Beat schon sagte - widme den Bestandteilen etwas mehr Aufmerksamkeit, anstatt sie "in einem Rutsch" abzuhandeln.

    Beispiele:

    9°55'55.71"O
    9°55'55.71" ö.L.
    9°55.95'E

    Also hast du grundlegend erst Mal folgende Bestandteile:

    • Zahl gefolgt von Gradzeichen
    • Zahl gefolgt von Minutenzeichen
    • Zahl gefolgt von Sekundenzeichen
    • Buchstaben, die noch den Quadranten angeben

    Ueberlege dir, welche dieser Bestandteile ggf. optional vorhanden sein koennten - der erste und der letzte vermutlich nicht, die anderen koennen aber vielleicht auch fehlen.
    Dann ueberleg dir noch, ob und wo dazwischen du ggf. noch optionalen Whitespace akzeptieren willst.

    MfG ChrisB

    --
    „This is the author's opinion, not necessarily that of Starbucks.“
    1. Hallo,

      Beispiele:
      9°55'55.71"O
      9°55'55.71" ö.L.
      9°55.95'E

      Also hast du grundlegend erst Mal folgende Bestandteile:

      • Zahl gefolgt von Gradzeichen
      • Zahl gefolgt von Minutenzeichen
      • Zahl gefolgt von Sekundenzeichen
      • Buchstaben, die noch den Quadranten angeben

      und ihr habt das Vorzeichen vergessen.

      Ueberlege dir, welche dieser Bestandteile ggf. optional vorhanden sein koennten - der erste und der letzte vermutlich nicht

      Warum nicht?
      Bei Koordinaten, die innerhalb von ±1° um den Nullmeridian bzw. den Äquator liegen, könnte die Angabe auch mit der Anzahl der Bogenminuten beginnen.
      Und die Buchstaben hintendran können ebenfalls fehlen, da man östliche Längen bzw. südliche Breiten ja auch gern einfach als negative Winkel notiert.

      Dann ueberleg dir noch, ob und wo dazwischen du ggf. noch optionalen Whitespace akzeptieren willst.

      Ich bin eher der Meinung, dass man hier mit Regex nicht zum Ziel kommt, sondern den gesamten String Stück für Stück analytisch parsen muss:
       * Führendes Vorzeichen (falls vorhanden)
       * Bis zu dreimal einen Block aus Ziffern und optional einem Dezimalpunkt
         isolieren und als float parsen, dann anhand des nachfolgenden Zeichens
         die Wertigkeit feststellen
       * abschließende Ost/West- bzw. Nord/Süd-Info auswerten
      Ich hab sowas vor Jahren mal in C geschrieben, dürfte aber in PHP auch nicht schwieriger sein.

      So long,
       Martin

      --
      Die Zeit, die man zur Fertigstellung eines Projekts wirklich braucht, ist immer mindestens doppelt so lang wie geplant.
      Wurde dieser Umstand bei der Planung bereits berücksichtigt, gilt das Prinzip der Rekursion.
      1. @@Der Martin:

        […] da man östliche Längen […] ja auch gern einfach als negative Winkel notiert.

        Tut man nicht.

        Merke: Osten positiv, Westen negativ. Wie im richtigen Leben. ;-)

        Live long and prosper,
        Gunnar

        --
        Das einzige Mittel, den Irrtum zu vermeiden, ist die Unwissenheit. (Jean-Jacques Rousseau)
        1. Hallo,

          […] da man östliche Längen […] ja auch gern einfach als negative Winkel notiert.
          Tut man nicht.
          Merke: Osten positiv, Westen negativ.

          das verwechsle ich immer wieder, weil in der Astronomie teilweise genau andersrum gezählt wird. Die Astronomen zählen ja auch das (gelegentlich auch "den") Azimut von Süden beginnend über Westen (Süd=0°, West=90°, Nord=180°, Ost=270°).

          Wie im richtigen Leben. ;-)

          Das verstehe ich nun nicht ganz. .oO(?)

          Schönes Wochenende,
           Martin

          --
          Schildkröten können mehr über den Weg berichten als Hasen.
    2. Ich komme grundsätzlich auf diese REGEX

      /(\d*[°'\"]\s?){1,3}/

      bei 9°55'55.71"O kommt dies raus:

      Array  
      (  
          [0] => 9°55'  
          [1] => 55  
          [2] =>  
          [3] => 71"  
          [4] =>  
          [5] =>  
      )
      

      Was das  soll weiss ich auch nicht, notfalls würde ich es aber in die eckigen klammern nehmen und das ? ändern... unglücklicher macht mich, dass meine exp 55.77 nicht zusammen kriegt.

      alles was ich weiter versuchen würde, geht in die richtung \d[,.]\d ... und das ist ja nicht so klasse.

      warte ... ICH HABS!!!

      /[0-9.,]+[°'\"]?\s?/

      Und Der Martin hat natürlich auch recht, Ich muss jetzt im zweiten durchgang matchen wo ° und ' und " vorkommen, um zu wissen was das für zahlen sind.

      1000dank für eure hilfe!!!!!!!!!!!

      1. warte ... ICH HABS!!!
        /[0-9.,]+[°'\"]?\s?/
        Und Der Martin hat natürlich auch recht, Ich muss jetzt im zweiten durchgang matchen wo ° und ' und " vorkommen, um zu wissen was das für zahlen sind.

        1000dank für eure hilfe!!!!!!!!!!!

        Also den Dank für deine Beratungsresistenz brauchst du nicht aussprechen.
        Solange bei dir die Zeichen [°'"] in einer Zeichenklasse gemeinsam vorkommen erachte ich deine Versuche als gescheitert.

        mfg Beat

        --
        Woran ich arbeite:
        X-Torah
        ><o(((°>           ><o(((°>
           <°)))o><                     ><o(((°>o
        1. Also den Dank für deine Beratungsresistenz brauchst du nicht aussprechen.
          Solange bei dir die Zeichen [°'"] in einer Zeichenklasse gemeinsam vorkommen erachte ich deine Versuche als gescheitert.

          Ich will ja auch die einzelnen Werte einer Geoposition haben und nicht aus einem $tring Geopositionen filtern. Habe ich mich in meinem ersten Beitrag so missverständlich ausgedrückt oder habe ich nicht verstanden wie du das machen würdest?

          schreib doch einfach mal wie das gehen soll, wenn nciht auf ZAHL eines der Zeichen folgen soll? Wie kann ich denn ZAHL[°'"] matchen, wenn die nicht in einer klasse sind? Ich will nicht ZAHL°ZAHL'ZAHL" finden, sondern alle Zahlen die vor eines der drei Zeichen stehen.

          Aber wahrscheinlich verstehe ich dich einfach nur falsch, denn lesen wirste ja wohl können.

          1. schreib doch einfach mal wie das gehen soll, wenn nciht auf ZAHL eines der Zeichen folgen soll? Wie kann ich denn ZAHL[°'"] matchen, wenn die nicht in einer klasse sind? Ich will nicht ZAHL°ZAHL'ZAHL" finden, sondern alle Zahlen die vor eines der drei Zeichen stehen.

            Dann suchst du nicht eine Geopositionsangabe sondern etwas Disparates.
            Verlässlichkeit kommt durch verlässliche Muster. Basta

            In Perl

            $geopos =~ m/
                ^         # falls du es mit einer Variable hast
                ( [+-]? )   # $1 Vorzeichen
                (?:
                  (         # $2
                  1?[0-9][0-9]   # geopositionen gehen bis +/- 180 Grad
                  )
                  °
                )?           # optional
                (?:
                  (         # $3
                  [1-5][0-9]   # 59 Minuten ist di höchste Minutenangabe
                  )
                  '
                )?           # optional
                (?:
                  (         # $4
                  [1-5][0-9]   # 59 Sekunden ist der höchste ganzzahlige Sekundenanteil
                   (?:          # optional Nachkomma
                     [,.]
                     [0-9]{1,3}
                   )?           # optional
                  )
                )?           # optional
                "
                \s?          #optional Whitespace
                (?-i:e|ö|w|n|s).[LlBb].   # Engisch/Deutsch
            /x;

            Die Frage ob Grade Minuten oder Sekunden optional sind, oder auch für Greenwich Pflicht, musst du selber wissen.

            Zur Umwandlung nach PHP einfach allen Whitespace entfernen.

            Ich behaupte nicht, dass dies ein normativer String für Geopositionen ist. Ich behaupte aber, dass dies die Richtige Form einer regex ist, welche dir mindestens etwas verlässliches zurückgeben kann, wenn auch eventuell einen leeren Inhalt.
            Du wirst immer in $1 ein Vorzeichen haben oder nichts
            Du wirst immer in $2 eine Gradangabe haben oder nichts
            ..
            ..

            mfg Beat

            --
            Woran ich arbeite:
            X-Torah
            ><o(((°>           ><o(((°>
               <°)))o><                     ><o(((°>o
            1. schreib doch einfach mal wie das gehen soll, wenn nciht auf ZAHL eines der Zeichen folgen soll? Wie kann ich denn ZAHL[°'"] matchen, wenn die nicht in einer klasse sind? Ich will nicht ZAHL°ZAHL'ZAHL" finden, sondern alle Zahlen die vor eines der drei Zeichen stehen.

              Dann suchst du nicht eine Geopositionsangabe sondern etwas Disparates.
              Verlässlichkeit kommt durch verlässliche Muster. Basta

              In Perl

              $geopos =~ m/
                  ^         # falls du es mit einer Variable hast
                  ( [+-]? )   # $1 Vorzeichen
                  (?:
                    (         # $2
                    1?[0-9][0-9]   # geopositionen gehen bis +/- 180 Grad

              Richtig, allerdings ist 090° doch auch eine korrekte Angabe, richtig? Und 90,0°?

            2. Dann suchst du nicht eine Geopositionsangabe sondern etwas Disparates.

              Ich weiss nicht was Disparates sind aber wahrscheinlich meinte ich das mit "Ich versuche grade eine Geoposition in ihre bestandteile zu zerlegen." in meinem ersten posting.

              Verlässlichkeit kommt durch verlässliche Muster. Basta

              In Perl

              $geopos =~ m/
                  ^         # falls du es mit einer Variable hast
                  ( [+-]? )   # $1 Vorzeichen
                  (?:
                    (         # $2
                    1?[0-9][0-9]   # geopositionen gehen bis +/- 180 Grad
                    )
                    °
                  )?           # optional
                  (?:
                    (         # $3
                    [1-5][0-9]   # 59 Minuten ist di höchste Minutenangabe
                    )
                    '
                  )?           # optional
                  (?:
                    (         # $4
                    [1-5][0-9]   # 59 Sekunden ist der höchste ganzzahlige Sekundenanteil
                     (?:          # optional Nachkomma
                       [,.]
                       [0-9]{1,3}
                     )?           # optional
                    )
                  )?           # optional
                  "
                  \s?          #optional Whitespace
                  (?-i:e|ö|w|n|s).[LlBb].   # Engisch/Deutsch
              /x;

              Die Frage ob Grade Minuten oder Sekunden optional sind, oder auch für Greenwich Pflicht, musst du selber wissen.

              WOW! Ich wollte zwar die Position nicht auf gültigkeit überprüfen und bei den Graden und Minuten können auch nachkommastellen kommen, aber trotzdem gibt Deine Lösung für mich als Anfänger einige interessante impulse, von denen ich sicher einige in mein REGEX aufnehmen werde.

              Dafür vielen Dank.

  3. @@Boris:

    [°'"]

    Ähm, du willst nach den falschen Zeichen suchen, nach den richtigen ′ (U+2032 PRIME) und ″ (U+2033 DOUBLE PRIME) jedoch nicht?

    Und vermutlich bist du mit strtok() besser dran als mit einem regulären Ausdruck.

    Live long and prosper,
    Gunnar

    --
    Das einzige Mittel, den Irrtum zu vermeiden, ist die Unwissenheit. (Jean-Jacques Rousseau)
    1. Hellihello

      Und vermutlich bist du mit strtok() besser dran als mit einem regulären Ausdruck.

      An so einen Ansatz dachte ich auch. Mit strpos die Postition von feststellen und dann mit substr den String abschneiden.

      if(strpos($gradstring,"+") !== false) (oder === 0) => halte fest: es beginnt mit Pluseichen. => Schneide Pluszeichen weg (evtl. auch mit str_replace)...;

      Dann weiter mit Grad-Zeichen, wieder abschneiden, dann Sekunden etc.pp.

      Aber wenn ich das richtig sehe, ist strtok dafür noch besser geeignet bzw. fasst genau diese Funktionen zusammen.

      Dank und Gruß,

      frankx

      --
      tryin to multitain  - Globus = Planet != Welt
    2. @@Boris:

      [°'"]

      Ähm, du willst nach den falschen Zeichen suchen, nach den richtigen ′ (U+2032 PRIME) und ″ (U+2033 DOUBLE PRIME) jedoch nicht?

      Ich war mir nicht bewusst, dass das natürlich wichtig ist. Aber ich glaube ich muss dann alle möglichen und unmöglichen zeichen zulassen weil es nicht sooo eindeutig ist wie min und sec. markiert werden, also: [′'‵] und [″"
      ‶]

      Und vermutlich bist du mit strtok() besser dran als mit einem regulären Ausdruck.

      äh? .. jaklar! (klatsch)!! jetzt wird mir auch klar warum Beat davon ausgegangen ist, dass ich ganze geopositionen filtern will. Ich denke auch mal dass strtok()schneller ist als mein ganzes gemöhre.

      Danke!

      1. @@Boris:

        Aber ich glaube ich muss dann alle möglichen und unmöglichen zeichen zulassen

        Frei nach Goscinny: Alle? Nein! ;-)

        Statt ° (U+00B0 DEGREE SIGN) könnten Nutzer fälschlicherweise º (U+00B6 MASCULINE ORDINAL INDICATOR) verwenden;
        statt ′ (U+2032 PRIME) oder ' (U+0027 APOSTROPHE) könnte auch ’ (U+2019 RIGHT SINGLE QUOTATION MARK) kommen;
        statt ″ (U+2033 DOUBLE PRIME) oder " (U+0022 QUOTATION MARK) auch ” (U+201D RIGHT DOUBLE QUOTATION MARK), aber auch ′′ (U+2032 U+2032).

        Damit dürfte das Wesentliche erfasst sein, du kannst aber natürlich beliebig viel Aufwand betreiben.

        Vielleicht möchtest du auch "52deg 31min 5sec" oder "13d27m43s" zulassen?

        Live long and prosper,
        Gunnar

        --
        Das einzige Mittel, den Irrtum zu vermeiden, ist die Unwissenheit. (Jean-Jacques Rousseau)