Rebecca: Regular Expression für ein Datum

Hallo liebe SelfHtml Gemeinde,

ich möchte eine regular Expression für ein Datum festlegen, habe aber ein kleines Problem.

Folgender Fall:

um auf ein Datum im Format tt/mm/jjjj oder tt-mm-jjjj herauszufinden verwende ich folgende regular expression:

/^\d\d[/-]\d\d[/-]\d\d\d\d$/
Das funktioniert soweit wunderbar.

Nun möchte ich aber, dass das Datum auch im Format tt.mm.jjjj gefunden wird, also mit dem Punkt "." als Trennzeichen.

Kopfzerbrechen bereiten mir die beiden Teile: [/-]
Hiermit finde ich nämlich die Trennzeichen "/" und "-" im Datum.

Das bedeutet demnach soviel wie "/" ODER "-". Wenn ich nun ein weiteres ODER (für den Punkt als Trennzeichen) hinzufügen möchte müsste es demnach heissen: [/-.], richtig? Das funktioniert aber nicht. Ich habe auch [/.-] schon ausprobiert.

Kann mir hierbei jemand weiter helfen?
Vielen Dank im Voraus

Liebe Grüße
Rebecca

  1. Das bedeutet demnach soviel wie "/" ODER "-". Wenn ich nun ein weiteres ODER (für den Punkt als Trennzeichen) hinzufügen möchte müsste es demnach heissen: [/-.], richtig? Das funktioniert aber nicht. Ich habe auch [/.-] schon ausprobiert.

    Du musst, soweit ich weiß, nur '/' innerhalb der eckigen Klammern maskieren.
    Struppi.

    1. Hallo Struppi,
      danke für die Antwort.

      Du musst, soweit ich weiß, nur '/' innerhalb der eckigen Klammern maskieren.

      wenn ich aber [/-.] verwende erscheint eine Fehlermeldung "invalid range in character class". Was bedeutet das?

      Ich habe nun [./-] verwendet und es funktioniert.
      Danke

      Liebe Grüße
      Rebecca

      1. gudn tach!

        Du musst, soweit ich weiß, nur '/' innerhalb der eckigen Klammern maskieren.

        brackets und minus-zeichen u.u. auch.

        wenn ich aber [/-.] verwende erscheint eine Fehlermeldung "invalid range in character class". Was bedeutet das?

        mit dem - gibt man in character classes (zeichenklassen), also den in brackets (eckigen klammern) eingeschlossenen zeichen, einen bereich (range) an.
        beispiele:
        [2-6] ist die zeichenklasse der ziffern 2 bis 6, man koennte auch [23456] schreiben.
        [a-z] ist die zeichenklasse der zeichen a bis z, also der 26 konventionellen kleinbuchstaben.
        "invalid range in character class" heisst also, dass der bereich [/-.], also alle zeichen vom / bis zum ., nicht zugelassen ist.

        wenn das - nicht als "bis" verwendet werden soll, muss es maskiert werden oder z.b. am ende der klasse stehen.[1]

        Ich habe nun [./-] verwendet und es funktioniert.

        wundert mich. eigentlich haette ich erwartet, dass eine fehlermeldung kommt a la "end of character class expected".

        [1] link zum thema, mit mehr details

        prost
        seth

        1. gudn tach!

          Du musst, soweit ich weiß, nur '/' innerhalb der eckigen Klammern maskieren.

          brackets und minus-zeichen u.u. auch.

          nee. "auch" stimmt nicht. '/' braucht innerhalb von character classes nicht maskiert zu werden.

          prost
          seth

        2. Hell-O!

          brackets und minus-zeichen u.u. auch.

          Ja, aber nicht zwingend, kommt drauf an, wo sie stehen. Übrigens, kennst du einen Anwendungsfall, in dem der Slash in einer Zeichenklasse maskiert werden müsste? Mir ist jedenfalls keiner bekannt.

          wenn das - nicht als "bis" verwendet werden soll, muss es maskiert werden oder z.b. am ende der klasse stehen.[1]

          Oder am Anfang.

          [1] link zum thema, mit mehr details

          Link zu den Details ;-)

          prost

          Mahlzeit.

          Siechfred

          1. gudn tach!

            brackets und minus-zeichen u.u. auch.

            Ja, aber nicht zwingend, kommt drauf an, wo sie stehen.

            u.u. = unter umstaenden. ;-)

            Übrigens, kennst du einen Anwendungsfall, in dem der Slash in einer Zeichenklasse maskiert werden müsste?

            habe mich noch nach ingrid-manier korrigiert.
            aber das back-slash muss iirc u.u. maskiert werden ([x\d] vs. [x\d]).

            wenn das - nicht als "bis" verwendet werden soll, muss es maskiert werden oder z.b. am ende der klasse stehen.[1]

            Oder am Anfang.

            ...oder z.b. zwischen \d und \w (innerhalb einer klassendefinition)... deswegen habe ich "z.b." geschrieben und die fussnote gesetzt. ;-p

            prost
            seth

          2. gudn tach!

            kennst du einen Anwendungsfall, in dem der Slash in einer Zeichenklasse maskiert werden müsste? Mir ist jedenfalls keiner bekannt.

            Struppi berichtet afais von sowas.

            prost
            seth

            1. kennst du einen Anwendungsfall, in dem der Slash in einer Zeichenklasse maskiert werden müsste? Mir ist jedenfalls keiner bekannt.

              Struppi berichtet afais von sowas.

              Ich weiß auch nicht wie ich die Fehler anders deuten soll:

              Ich hab auf den Seiten einen Error Log eingebaut:

              Borwser String: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060130 Red Hat/1.7.12-1.4.2
              Fehler: unterminated character class
              Zeile: 188
              Datei: http://javascript.jstruebig.de/javascript/39/

              Die Zeile sah vormals so aus:
              string = string.replace(/[-/]/g, '.'); // Trennzeichen normalisieren

              Struppi.

              1. gudn tach!

                Ich hab auf den Seiten einen Error Log eingebaut:

                oh, das ist ja geil!

                Borwser String: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060130 Red Hat/1.7.12-1.4.2

                hui, ist der fehler von heute nachmittag so zwischen 14:00 und 15:00? dann koennte ich das gewesen sein? bei mir funzte das script naemlich nicht, aber aus zeitgruenden habe ich mich nicht naeher damit befasst. ich kann am montag noch mal danach schauen.

                prost
                seth

                1. Ich hab auf den Seiten einen Error Log eingebaut:

                  oh, das ist ja geil!

                  Alles geklaut :-)
                  Weiß aber nicht mehr woher

                  Borwser String: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20060130 Red Hat/1.7.12-1.4.2

                  hui, ist der fehler von heute nachmittag so zwischen 14:00 und 15:00? dann koennte ich das gewesen sein? bei mir funzte das script naemlich nicht, aber aus zeitgruenden habe ich mich nicht naeher damit befasst. ich kann am montag noch mal danach schauen.

                  Ja: http://jstruebig.de/cgi-bin/jserror.pl?read=1

                  Struppi.

              2. Hell-O!

                Struppi berichtet afais von sowas.
                Ich weiß auch nicht wie ich die Fehler anders deuten soll:
                Fehler: unterminated character class

                Den es sinnigerweise nur bei string.replace gibt. Scheinbar verwirrt Javascript (und nur Javascript!) der zweite Slash, der nach dort geltender Lesart den RegExp beendet. Leider scheint JS keinen anderen Begrenzer zu akzeptieren. Ich habe das mal kurz getestet:

                var foo = window.prompt('Foo sei ...');  
                // hier muss nichts maskiert werden:  
                var re = new RegExp('^[0-9][-./][0-9]$');  
                if(re.test(foo)) alert(foo+' passt');  
                else alert(foo+' passt nicht');  
                // hier muss zwingend der Slash maskiert werden:  
                foo = foo.replace(/[-.\/]/, '#');  
                alert(foo);
                

                Zusammengefasst scheint es zu bedeuten:

                Wird ein neues RegExp-Objekt erzeugt, verhält sich die Zeichenklasse wie von mir aus der Perl-Welt erwartet. Sobald man den RegExp ungequoted in einem replace, match oder search notiert bzw. die JS-eigene Automatik zur Erzeugung eines Regulären Ausdrucks (var re = /whatever/;) nutzt, ist jeder Slash, der kein Begrenzer ist, zumindest in JS zwingend zu maskieren.

                Aber vielleicht ergeben eure Tests ja noch was ganz anderes.

                Siechfred

                1. gudn tach!

                  Scheinbar verwirrt Javascript (und nur Javascript!) der zweite Slash, der nach dort geltender Lesart den RegExp beendet.

                  s/scheinbar /anscheinend /i
                  s/(.+!) //

                  in perl kann das auch zu problemen fuehren:

                  text.pl

                    
                  1 #!/usr/bin/perl  
                  2 use strict;  
                  3  
                  4 my $str='/prost/seth/';  
                  5 $str=~s/[/]/\n/g;  
                  6 print $str;
                  

                  $ ./text.pl
                  Unmatched [ in regex; marked by <-- HERE in m/[ <-- HERE / at text.pl line 5.

                  dagegen:
                  text.pl

                    
                  1 #!/usr/bin/perl  
                  2 use strict;  
                  3  
                  4 my $str='/prost/seth/';  
                  5 $str=~s/[\/]/\n/g;  
                  6 print $str;
                  

                  $ ./text.pl

                  prost
                  seth

                  1. Hell-O!

                    in perl kann das auch zu problemen fuehren:

                    Ja, du hast Recht. Allerdings stellte sich bei mir bisher nicht das Problem, da ich als Begrenzer immer etwas nehme, was im RegExp selber nicht vorkommt (meistens die Tilde), um mir soweit möglich das leidige Maskieren zu ersparen.

                    $str=~s/[/]/\n/g;

                    Sähe bei mir dann so aus:

                    $str =~ s~[/]~\n~g;

                    und funktioniert ohne Maskierung und ohne Fehlermeldung. Wie gesagt, JS scheint aber keinen anderen Begrenzer als den Slash zu akzeptieren.

                    Siechfred

  2. Hell-O!

    Nun möchte ich aber, dass das Datum auch im Format tt.mm.jjjj gefunden wird, also mit dem Punkt "." als Trennzeichen.

    Gut, dass du deine Zeichenklasse erweitern musst, hast du schon erkannt. Wie Struppi dir schon sagte, müssen Sonderzeichen in Zeichenklassen nicht maskiert werden.

    /^\d\d[/-]\d\d[/-]\d\d\d\d$/
    Kopfzerbrechen bereiten mir die beiden Teile: [/-]

    Möchtest du nicht lieber Quantifier verwenden? Dann sähe es so aus:

    /^\d{2}[/.-]\d{2}[/.-]\d{4}$/

    Allerdings akzeptiert dieser RegExp auch ein Datum wie "99.00.8652", willst du das?

    Das bedeutet demnach soviel wie "/" ODER "-". Wenn ich nun ein weiteres ODER (für den Punkt als Trennzeichen) hinzufügen möchte müsste es demnach heissen: [/-.], richtig? Das funktioniert aber nicht. Ich habe auch [/.-] schon ausprobiert.

    Was genau funktioniert nicht? Welche Programmiersprache verwendest du? Gibt es eine Fehlermeldung?

    Siechfred

    1. Hallo,
      danke für die Antwort.

      Möchtest du nicht lieber Quantifier verwenden? Dann sähe es so aus:

      /^\d{2}[/.-]\d{2}[/.-]\d{4}$/

      Das kannte ich noch nicht. Schaut besser aus, ja.

      Allerdings akzeptiert dieser RegExp auch ein Datum wie "99.00.8652", willst du das?

      Nein das will ich nicht. Das war aber auch im Format /d/d/d/d auch der Fall. Kann man das mit RegExp einschränken, so dass nur Jahreszahlen von 0000 bis 2099 möglich sind? Ob es Sinn macht weiss ich allerdings noch nicht;-)

      Was genau funktioniert nicht? Welche Programmiersprache verwendest du? Gibt es eine Fehlermeldung?

      Es kam die Meldung "Invalid Range in character class". Das ganze in JavaScript. Ich hab allerdings [./-] verwendet und so funktionierts. Nun werden die Trennzeichen "/", "-" und "." akzeptiert.

      Liebe Grüße
      Rebecca

      1. Allerdings akzeptiert dieser RegExp auch ein Datum wie "99.00.8652", willst du das?
        Nein das will ich nicht. Das war aber auch im Format /d/d/d/d auch der Fall. Kann man das mit RegExp einschränken, so dass nur Jahreszahlen von 0000 bis 2099 möglich sind? Ob es Sinn macht weiss ich allerdings noch nicht;-)

        Ja, das geht mit Lookarounds.

        Es kam die Meldung "Invalid Range in character class". Das ganze in JavaScript.

        Du hast nicht bedacht, dass ein "-" innerhalb einer Zeichenklasse ein "von ... bis" kennzeichnet. Schreibst du beispielsweise "[0-9]", beinhaltet die Zeichenklasse die Ziffern 0 bis 9. Wenn du schreibst [/-.], interpretiert Javascript dies als "alle Zeichen vom Slash bis zum Punkt", was aber falsch ist, da laut ASCII-Tabelle erst der Punkt und dann der Slash kommt. Ergo ist ein "von ... bis" unlogisch, was Javascript dir mit der Fehlermeldung signalisiert hat. Auf die Besonderheit des Bindestrichs hatte ich in diesem Posting schon hingewiesen.

        Ich hab allerdings [./-] verwendet und so funktionierts.

        Ja, weil der Bindestrich am Ende steht und somit nicht die Funktion eines "von ... bis" haben kann. Übrigens erlaubst du auch den Backslash als Trennzeichen, es sei denn, es soll der Maskierung dienen, die jedoch innerhalb von Zeichenklassen nicht nötig ist. Deine Zeichenklasse sieht daher so aus: "[/.-]".

        Siechfred

        1. Hallo Siechfried,

          vielen Dank für Deine Antwort. Scheinst ein Profi in Sachen regular expressions zu sein.

          Dein Posting war sehr detailliert und aufschlußreich.

          Liebe Grüße
          Rebecca

      2. echo $begrüßung;

        Allerdings akzeptiert dieser RegExp auch ein Datum wie "99.00.8652", willst du das?
        Nein das will ich nicht. [...] Kann man das mit RegExp einschränken, so dass nur Jahreszahlen von 0000 bis 2099 möglich sind? Ob es Sinn macht weiss ich allerdings noch nicht;-)

        Damit löst du vielleicht das Jahreszahlenproblem. Den Monat zu prüfen ist auch noch einfach. Aber nun geht es mit dem Tag weiter. Der ist abhängig von Monat und Jahr. Mit einer RegExp kannst du nicht rechnen. Zum Beispiel ist das Prüfen auf Durch-4-Teilbarkeit ist nicht möglich. Damit stößt du an die Grenzen einer Musterprüfung.

        Wenn du die Datumsprüfung nicht nur zum Üben machst, schlage ich vor, dass du dir eine fertige Datumsklasse oder Datumsprüffunktion für deine Programmiersprache suchst oder selbst programmierst.

        echo "$verabschiedung $name";

        1. Hello out there!

          Mit einer RegExp kannst du nicht rechnen. Zum Beispiel ist das Prüfen auf Durch-4-Teilbarkeit ist nicht möglich.

          Na aber sicher ist es das.

          Ich hab vor ein paar Tagen mal einen deterministischen endlichen Automaten (DFA) gebaut, der Daten (ISO 8601) erkennt (incl. Schaltjahrregel). Die Mengen der von DFAs erkannten Sprachen (Eingaben) und der von regulären Ausdrücken erkannten sind identisch – das ist die Menge der regulären (Typ 3 in der Chomsky-Hierarchie) Sprachen.

          Also gibt es auch einen regulären Ausdruck für Daten. Wie komplizeiert der ist, ist eine andere Frage.

          See ya up the road,
          Gunnar

          --
          “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
          1. Hello out there!

            Mit einer RegExp kannst du nicht rechnen. Zum Beispiel ist das Prüfen auf Durch-4-Teilbarkeit ist nicht möglich.

            Na aber sicher ist es das.

            ... denn bei der Teilbarkeit durch 4 ist gar kein Rechnen erforderlich, sondern nur Zeichenverarbeitung; wie bei der Teilbarkeit durch alle Zahlen der Form [latex]2^m \cdot 5^n \quad (m, n \in \mathbb{N})[/latex]

            Bei m = n (Teilbarkeit durch Zehnerpotenzen) ist es trivial: \d*0$ matcht alle durch 10 teilbaren Zahlen usw.

            Bei m = n + 1 auch einfach: \d*[05]$ matcht alle durch 5 teilbaren Zahlen

            Bei m = n - 1 auch einfach: \d*[02468]$ matcht alle durch 2 teilbaren Zahlen

            Bei m = n + 2 und m = n - 2 (z.B. Teilbarkeit durch 25 bzw. 4) muss man sich noch die vorletzte Stelle mit ansehen, bei noch größerer Differenz zwischen m und n entsprechend mehr.

            Je größer die Differenz zwischen m und n ist, desto komplizierter wird der reguläre Ausdruck, aber möglich ist es immer.

            See ya up the road,
            Gunnar

            --
            “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
      3. Hello out there!

        Kann man das mit RegExp einschränken, so dass nur Jahreszahlen von 0000 bis 2099 möglich sind? Ob es Sinn macht weiss ich allerdings noch nicht;-)

        Wenn du auf ein gültiges Datum prüfen willst, muss du auch die unterschiedlichen Monatslängen berücksichtigen, dazu auch Schaltjahre, je nach Zeitrahmrn dabei auch die 400-Jahre-Regel.

        All das geht mit einem regulären Ausdruck, der aber ziemlich kopliziert sein dürfte. Ob es Sinn macht ...

        See ya up the road,
        Gunnar

        --
        “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
  3. Hello out there!

    ich möchte eine regular Expression für ein Datum festlegen, habe aber ein kleines Problem.
    […] tt/mm/jjjj oder tt-mm-jjjj […] auch im Format tt.mm.jjjj

    Willst du damit eine Eingabe in einem Formularfeld prüfen? Dann hast du noch ein Problem; besser gesagt der Nutzer, der das Datum im nach DIN 5008 gültigen Datumsformat jjjj-mm-dd gemäß ISO 8601 eingibt. Willst du einem Nutzer vorschreiben, das vernünftigste aller Datumsformate nicht zu benutzen?

    See ya up the road,
    Gunnar

    --
    “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
  4. ich möchte eine regular Expression für ein Datum festlegen, habe aber ein kleines Problem.

    Mittlerweile Wissen wir, dass du vermutlich lieber das Datum überprüfen willst. Das geht nicht mit einer RegExp.

    Folgender Fall:

    um auf ein Datum im Format tt/mm/jjjj oder tt-mm-jjjj herauszufinden verwende ich folgende regular expression:

    Um ein Datum zu überprüfen, verwende ich folgende Funktion http://javascript.jstruebig.de/javascript/39/

    Struppi.

    1. Hello out there!

      Mittlerweile Wissen wir, dass du vermutlich lieber das Datum überprüfen willst. Das geht nicht mit einer RegExp.

      Und es geht doch.

      See ya up the road,
      Gunnar

      --
      “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
      1. Hello out there!

        Was gab’s da auf „nicht hilfreich“ zu clicken? Meine Aussage war lediglich die Berichtigung von Struppis, dass das Prüfen einer Eingabe auf ein gültiges Datum nicht mit einem regulären Ausdruck ginge; denn es geht.

        Ich wollte keineswegs andeuten, dass man es damit tun sollte.

        See ya up the road,
        Gunnar

        --
        “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
        1. echo $begrüßung;

          Was gab’s da auf „nicht hilfreich“ zu clicken?

          Ich weiß es nicht.

          Meine Aussage war lediglich die Berichtigung von Struppis, dass das Prüfen einer Eingabe auf ein gültiges Datum nicht mit einem regulären Ausdruck ginge; denn es geht.

          Auch wenn die Aussage richtig ist, kann sie doch nicht hilfreich sein.

          Ich könnte mir als Gründe folgende vorstellen:

          • Theoretisch mag es mit einigem Aufwand möglich sein, eine vollständige Datumsprüfung mit einem regulärem Ausdruck durchzuführen. Wenn ich mir das richtig ausmale kommt da einiges an Zeichen zusammen. Reguläre Ausdrücke sind so schon nicht leicht zu lesen und du willst theoretisch einen erstellen, der mit jeder Menge Zeichen aufgebläht ist, die diverse Teilbarkeitsmuster gefolgt (lookahead) oder vorangegangen (lookbehind) von [schlagmichtot] enthalten - also quasi querbeet durch sämtliche RegExp-Möglichkeiten gehend. Ist sicher theoretisch alles möglich, aber praktisch nicht sehr hilfreich, weil man das eigentliche Ziel mit 3 Zeilen Programmtext einfacher und durchschaubarer erreichen kann.
          • Jemand hat sich verklickt.

          Ich wollte keineswegs andeuten, dass man es damit tun sollte.

          Gut. Ich will mich auch nicht mit dir streiten, weil ich sowieso nicht mehr mithalten kann/will wenn du in die höheren Sphären der Mathematik abdriftest. Aber wenn du Zeit und Muße hast, kannst du ja mal so eine schaltjahrberücksichtigende Datums-RegExp erstellen. Die Kalenderkorrekturen längst vergangener Jahrhunderte kannst du ja für den Anfang erst einmal unberücksichtigt lassen. :-)

          echo "$verabschiedung $name";

          1. Hello out there!

            Aber wenn du Zeit und Muße hast, kannst du ja mal so eine schaltjahrberücksichtigende Datums-RegExp erstellen. Die Kalenderkorrekturen längst vergangener Jahrhunderte kannst du ja für den Anfang erst einmal unberücksichtigt lassen. :-)

            -?\d*(?:(?:(?:(?:[02468][048]|[13579][26])(?:[02468][048]|[13579][26])|(?:[02468][^048]|[13579][^26])(?:0[48]|[2468][048]|[13579][26]))[-./]?02[-./]?(?:0[1-9]|[12]\d)|(?:(?:[02468][^048]|[13579][^26])00|\d\d(?:[02468][^048]|[13579][^26]))[-./]?02[-./]?(?:0[1-9]|12\d|2[0-8]))|\d{4}[-./]?(?:(?:0[13578]|1[02])[-./]?(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)[-./]?(?:0[1-9]|[12]\d|30)))

            Na, so schwer war’s doch gar nicht. ;-)

            Der Ausdruck passt auf gültige Daten im Format ISO 8601 (heutige Schaltjahrregel auf gesamten Bereich angewandt). Der Audruck lässt '-', '.' oder '/' als Trennzeichen zu oder auch kein Trennzeichen. Da haben wir ein Manko: Der Ausdruck erkennt nicht, ob zwischen Jahr und Monat sowie zwischen Monat und Tag dasselbe Trennzeichen steht (2006.03/25 würde auch matchen). Ließe sich mit einigem Aufwand beheben (statt foo[-./]?bar[-./]?baz dann foo-bar-baz|foo\.bar\.baz|foo/bar/baz|foobarbaz).

            Zur Erklärung:

            -?\d*                                        # für die Ewigkeit
            (?:
              (?:
                (?:
                  (?:[02468][048] | [13579][26])         # Jahrhundert durch 4 teilbar
                  (?:[02468][048] | [13579][26])         # Jahr duch 4 teilbar
                  |
                  (?:[02468][^048] | [13579][^26])       # Jahrhundert nicht durch 4 teilbar
                  (?:0[48] | [2468][048] | [13579][26])  # Jahr duch 4 teilbar außer volle Jahrhunderte
                )
                [-./]?                                   # Trennzeichen
                02                                       # Februar im Schaltjahr
                [-./]?                                   # Trennzeichen
                (?:0[1-9] | [12]\d)                      # 01 bis 29
                |
                (?:
                  (?:[02468][^048] | [13579][^26])       # Jahrhundert nicht durch 4 teilbar
                  00                                     # selbsterklärend
                  |
                  \d\d                                   # beliebiges Jahrhundert
                  (?:[02468][^048] | [13579][^26])       # Jahr nicht durch 4 teilbar
                )
                [-./]?                                   # Trennzeichen
                02                                       # Februar im Nicht-Schaltjahr
                [-./]?                                   # Trennzeichen
                (?:0[1-9] | 12\d | 2[0-8])               # 01 bis 28
              )
              |
              \d{4}                                      # beliebiges Jahr
              [-./]?                                     # Trennzeichen
              (?:
                (?:0[13578] | 1[02])                     # langer Monat
                [-./]?                                   # Trennzeichen
                (?:0[1-9] | [12]\d | 3[01])              # 01 bis 31
                |
                (?:0[469] | 11)                          # kurzer Monat
                [-./]?                                   # Trennzeichen
                (?:0[1-9] | [12]\d | 30)                 # 01 bis 30
              )
            )
            

            See ya up the road, Gunnar

            --
            “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
            1. Hello out there!

              Wäre auch zu schön gewesen ohne Fehler. So sollte’s passen:

              -?\d*(?:(?:(?:(?:[02468][048]|[13579][26])(?:[02468][048]|[13579][26])|(?:[02468][^048]|[13579][^26])(?:0[48]|[2468][048]|[13579][26]))[-./]?02[-./]?(?:0[1-9]|[12]\d)|(?:(?:[02468][^048]|[13579][^26])00|\d\d(?:[02468][^048]|[13579][^26]))[-./]?02[-./]?(?:0[1-9]|1\d|2[0-8]))|\d{4}[-./]?(?:(?:0[13578]|1[02])[-./]?(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)[-./]?(?:0[1-9]|[12]\d|30)))

              Eine '2' war zu viel (trotz Vorschau):

              (?:0[1-9] | 12\d | 2[0-8])               # 01 bis 28

              ^ die hier muss weg

              See ya up the road,
              Ingunnarid

              --
              “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
              1. gudn tach!

                -?\d*(?:(?:(?:(?:[02468][048]|[13579][26])(?:[02468][048]|[13579][26])|(?:[02468][^048]|[13579][^26])(?:0[48]|[2468][048]|[13579][26]))[-./]?02[-./]?(?:0[1-9]|[12]\d)|(?:(?:[02468][^048]|[13579][^26])00|\d\d(?:[02468][^048]|[13579][^26]))[-./]?02[-./]?(?:0[1-9]|1\d|2[0-8]))|\d{4}[-./]?(?:(?:0[13578]|1[02])[-./]?(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)[-./]?(?:0[1-9]|[12]\d|30)))

                geil!
                aaaber es sind noch immer fehler drin, weil durch die negierten zeichenklassen z.b. '2a04-02-01' zugelassen wird.

                -?\d*                                        # für die Ewigkeit

                lol! wenn also 9999-12-31 kurz nach 23:59 alles den bach runter geht, weil niemand der grossen betriebssystem-hersteller an das y10k-problem dachte, laeuft dein regexp noch munter weiter und streckt der anderen software die zunge heraus. ;-)

                es geht uebrigens noch kuerzer, wenn man die nicht-schaltjahre als teilmenge der menge der beliebigen jahre ansieht:

                /-?\d*(?:(?:(?:[02468][048]|[13579][26])(?:[02468][048]|[13579][26])|(?:[02468][1-35-79]|[13579][013-57-9])(?:0[48]|[2468][048]|[13579][26]))([-./]?)02\1 29|\d{4}([-./]?)(?:(?:0[13578]|1[02])\2(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)\2(?:0[1-9]|[12]\d|30)|02\2(?:0[1-9]|1\d|2[0-8])))/x

                bzw. kommentiert:

                  
                if($date=~/-?\d*  
                  (?:  
                    (?:                                     # 29. feb. im schaltjahr  
                      (?:[02468][048]|[13579][26])           # jahrhundert durch 4 teilbar  
                      (?:[02468][048]|[13579][26])           # jahr durch 4 teilbar  
                      |  
                      (?:[02468][1-35-79]|[13579][013-57-9]) # jahrhundert nicht durch 4 teilbar  
                      (?:0[48]|[2468][048]|[13579][26])      # jahr durch 4 teilbar ausser volle jahrhunderte  
                    )  
                    ([-.\/]?)                                # separator \1  
                    02\1 29                                  # 29. feb.; wiederholung des separators  
                    |  
                    \d{4}                                   # beliebiges jahr  
                    ([-.\/]?)                                # separator \2  
                    (?:  
                      (?:0[13578]|1[02])                     # langer monat  
                      \2                                     # wiederholung \2  
                      (?:0[1-9]|[12]\d|3[01])                # 01 bis 31  
                      |  
                      (?:0[469]|11)                          # kurzer monat  
                      \2                                     # wiederholung \2  
                      (?:0[1-9]|[12]\d|30)                   # 01 bis 30  
                      |  
                      02                                     # februar  
                      \2                                     # wiederholung \2  
                      (?:0[1-9]|1\d|2[0-8])                  # 01 bis 28  
                    )  
                  )/x){  
                  print 'valid'."\n";  
                }else{  
                  print 'not valid!';  
                }
                

                hierbei habe ich uebrigens durch backreferencing noch eingebaut, dass man zwei mal dasselbe trennzeichen (was noch immer iso-konform auch der leere string sein darf) verwenden muss.

                bei bedarf kann man noch ein ^ an den anfang und ein $ an das ende stellen, falls man nicht nur ein datum sucht, sondern wissen will, ob der komplette string eine datumsangabe sein koennte.

                jetzt hakt der test allerdings noch immer, weil der gregorianische kalender erst 1582 eingefuehrt (und deshalb z.b. der oktober 1582 radikal verkuerzt) wurde (siehe wikipedia).

                dadurch wuerde der check dann wieder etwas laenger werden. ich poste aber mal nur den teil, der fuer die jahre 1583 bis 9999 zustaendig waere. fuer die zusaetzlichen jahre ab 10000 koennte man beide ausdruecke (also den obigen und den folgenden) mit einem dicken OR kombinieren.

                  
                if($date=~/# laesst nur jahre 1583 bis 9999 zu  
                  (?:                                          # 29. feb. im schaltjahr  
                    (?:[2468][048]|16|[3579][26])               # jahrhundert durch 4 teilbar  
                    (?:[02468][048]|[13579][26])                # jahr durch 4 teilbar  
                    |  
                    (?:[2468][1-35-79]|1[789]|[3579][013-57-9]) # jahrhundert nicht durch 4 teilbar  
                    (?:0[48]|[2468][048]|[13579][26])           # jahr durch 4 teilbar ausser volle jahrhunderte  
                    |  
                    15(?:88|9[26])                              # beachtung der einfuehrung des gregor. kalenders  
                  )  
                  ([-.\/]?)                                     # separator \1  
                  02\1 29                                       # 29. feb.; wiederholung des separators \1  
                  |  
                  (?:[2-9]\d\d\d|1[6-9]\d\d|159\d|158[3-9])    # beliebiges jahr, ab 1583  
                  ([-.\/]?)                                     # separator \2  
                  (?:  
                    (?:0[13578]|1[02])                          # langer monat  
                    \2                                          # wiederholung \2  
                    (?:0[1-9]|[12]\d|3[01])                     # 01 bis 31  
                    |  
                    (?:0[469]|11)                               # kurzer monat  
                    \2                                          # wiederholung \2  
                    (?:0[1-9]|[12]\d|30)                        # 01 bis 30  
                    |  
                    02                                          # februar  
                    \2                                          # wiederholung \2  
                    (?:0[1-9]|1\d|2[0-8])                       # 01 bis 28  
                  )/x){  
                  print 'valid'."\n";  
                }else{  
                  print 'not valid!';  
                }
                

                getestet habe ich den kram jetzt allerdings nicht, das darf jemand anders machen. *duck*

                prost
                seth

                1. Hello out there!

                  aaaber es sind noch immer fehler drin, weil durch die negierten zeichenklassen z.b. '2a04-02-01' zugelassen wird.

                  Argl. Da wollte ich an der falschen Stelle ein paar Zeichen sparen.

                  Also [1235679] statt [^048]. [1-35-79] spart wohl nichts. Geht eigentlich auch sowas: [\d^048]?

                  weil niemand der grossen betriebssystem-hersteller an das y10k-problem dachte

                  LOL.

                  Eigentlich dachte ich an die heutigen Bedürfnisse – der Wahrsager, die heute schon das Ende der Welt für 10235-10-21T16:23Z vorhersagen.

                  jetzt hakt der test allerdings noch immer, weil der gregorianische kalender erst 1582 eingefuehrt

                  Das Wann ist abhängig vom Wo.

                  Und ja, das Problem war mir bewusst, das wollte ich mit „heutige Schaltjahrregel auf gesamten Bereich angewandt“ angedeutet haben.

                  hierbei habe ich uebrigens durch backreferencing noch eingebaut

                  Verdient das dann eigentlich noch den Namen „regulärer Ausdruck“ im Sinne der theoretischen Informatik? Oder werden damit nicht reguläre, sondern kontextsensitive Sprachen beschrieben? Mal nachdenken ...

                  See ya up the road,
                  Gunnar

                  --
                  “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
                  1. gudn tach Gunnar!

                    Also [1235679] statt [^048]. [1-35-79] spart wohl nichts.

                    ja, ist imho bloss etwas uebersichtlicher.

                    Geht eigentlich auch sowas: [\d^048]?

                    ja, aber es matcht nicht, was moechtest. innerhalb von zeichenklassen-definitionen gilt: negiert ^ die zeichenklasse nur dann, wenn es das erste zeichen nach [ ist. sonst hat es keine meta-bedeutung.

                    was du moechtest, laesst sich dennoch bewerkstelligen, und zwar mit dem alten hellseher-trick:
                    /(?=\d)[^048]/

                    (?=\d) verlangt, dass das naechste zeichen eine ziffer ist.
                    [^048] verlangt, dass das zeichen weder 0, 4 noch 8 sein darf.

                    weil niemand der grossen betriebssystem-hersteller an das y10k-problem dachte

                    LOL.

                    Eigentlich dachte ich an die heutigen Bedürfnisse – der Wahrsager, die heute schon das Ende der Welt für 10235-10-21T16:23Z vorhersagen.

                    aeh, hat das mit 10235 einen hintergrund? (man weiss ja nie.)

                    jetzt hakt der test allerdings noch immer, weil der gregorianische kalender erst 1582 eingefuehrt

                    Das Wann ist abhängig vom Wo.

                    ja, das ist wahr. aber ich dachte, dass (heutzutage) die daten vor 1582 normalerweise nicht nach dem greg. (sondern dem julianischen) kalender angegeben werden.
                    ach ja, und bei deinem regulaeren ausdruck war noch nicht beruecksichtigt, dass es das jahr 0 nicht gab.

                    Und ja, das Problem war mir bewusst [..]

                    wollte ich auch gar nicht infrage stellen, sondern bloss noch als verbesserung vorschlagen.

                    hierbei habe ich uebrigens durch backreferencing noch eingebaut

                    Verdient das dann eigentlich noch den Namen „regulärer Ausdruck“ im Sinne der theoretischen Informatik?

                    nein.

                    Oder werden damit nicht reguläre, sondern kontextsensitive Sprachen beschrieben? Mal nachdenken ...

                    beides.

                    prost
                    seth

                    1. Hello out there!

                      Also [1235679] statt [^048]. [1-35-79] spart wohl nichts.
                      ja, ist imho bloss etwas uebersichtlicher.

                      YMMV, aber ich erspare mir lieber die Überlegung, wofür der '-' steht.

                      dass es das jahr 0 nicht gab.

                      War mir auch so. Im aktuellen Wikipedia-Artikel las sich das aber anders. Aber schon möglich, dass der sich nicht auf eine aktuelle Version der ISO-Norm bezieht.

                      Doc Emmett Brown: “...or witness the birth of Christ?” ("DEC 25 0000" auf dem Display im DeLorean)

                      Oder werden damit nicht reguläre, sondern kontextsensitive Sprachen beschrieben? Mal nachdenken ...
                      beides.

                      :-) Ja, die Frage war ja schon blöd gestellt; Teilmenge und so. „nicht _nur_ reguläre“ hätt besser geklungen.

                      See ya up the road,
                      Gunnar

                      --
                      “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
                      1. gudn tach Gunnar!

                        dass es das jahr 0 nicht gab.

                        War mir auch so. Im aktuellen Wikipedia-Artikel las sich das aber anders. Aber schon möglich, dass der sich nicht auf eine aktuelle Version der ISO-Norm bezieht.

                        oh, ich hab's erst jetzt nachgelesen.
                        zumindest scheint es weitaus komplizierter (z.b. "Dieses Jahr Null beginnt am 3. Januar 1 vor und endet am 2. Januar 1 nach Christus") zu sein, als ich bisher annahm. nun gut, dann war dein jahr 0 wohl je nach norm doch kein fehler.

                        Doc Emmett Brown: “...or witness the birth of Christ?” ("DEC 25 0000" auf dem Display im DeLorean)

                        hihi, ist mir damals gar nicht aufgefallen, aber jetzt wo du's sagst...

                        prost
                        seth

        2. Was gab’s da auf „nicht hilfreich“ zu clicken?

          ich war''s nicht

          :-)

          Struppi.