Frage

Ich versuche, einen regulären Ausdruck zu schreiben, der ein Datum validiert.Der reguläre Ausdruck muss mit Folgendem übereinstimmen

  • M/T/JJJJ
  • MM/TT/JJJJ
  • Einstellige Monate können mit einer führenden Null beginnen (z. B.:12.03.2008)
  • Einstellige Tage können mit einer führenden Null beginnen (z. B.:3.02.2008)
  • Der 30. oder 31. Februar KANN NICHT enthalten sein (z. B.:31.02.2008)

Bisher habe ich

^(([1-9]|1[012])[-/.]([1-9]|[12][0-9]|3[01])[-/.](19|20)\d\d)|((1[012]|0[1-9])(3[01]|2\d|1\d|0[1-9])(19|20)\d\d)|((1[012]|0[1-9])[-/.](3[01]|2\d|1\d|0[1-9])[-/.](19|20)\d\d)$

Dies stimmt ordnungsgemäß überein, AUSSER es enthält immer noch den 30.02.2008 und den 31.02.2008.

Hat jemand einen besseren Vorschlag?

Bearbeiten: ich fand die Antwort auf RegExLib

^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$

Es entspricht allen gültigen Monaten, die dem Format MM/TT/JJJJ folgen.

Vielen Dank an alle für die Hilfe.

War es hilfreich?

Lösung

Dies ist keine angemessene Verwendung regulärer Ausdrücke.Sie sollten es besser verwenden

[0-9]{2}/[0-9]{2}/[0-9]{4}

und dann Bereiche in einer höheren Sprache überprüfen.

Andere Tipps

Hier ist der Reg-Ex, der mit allen gültigen Daten, einschließlich Schaltjahren, übereinstimmt.Akzeptierte Formate: mm/tt/jjjj oder mm-tt-jjjj oder mm.tt.jjjj

^(?:(?:(?:0?[13578]|1[02])(\/|-|\.)31)\1|(?:(?:0?[1,3-9]|1[0-2])(\/|-|\.)(?:29|30)\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:0?2(\/|-|\.)29\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\/|-|\.)(?:0?[1-9]|1\d|2[0-8])\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$

Anstand Asiq Ahamed

Ich bin hier gelandet, weil der Titel dieser Frage weit gefasst ist und ich nach einem regulären Ausdruck gesucht habe, den ich für die Übereinstimmung mit einem bestimmten Datumsformat (wie dem OP) verwenden kann.Doch dann entdeckte ich, wie viele der Antworten und Kommentare umfassend hervorgehoben haben, dass es viele Fallstricke gibt, die die Erstellung eines effektiven Musters sehr schwierig machen, wenn Daten extrahiert werden, die mit minderwertigen oder nicht strukturierten Quelldaten vermischt sind.

Bei meiner Untersuchung der Probleme habe ich ein System entwickelt, mit dem Sie einen regulären Ausdruck erstellen können, indem Sie vier einfachere Unterausdrücke zusammenstellen, die hinsichtlich des Trennzeichens und gültiger Bereiche für die Felder Jahr, Monat und Tag in der Reihenfolge übereinstimmen du benötigst.

Diese sind :-

Demeter

[^\w\d\r\n:] 

Dies entspricht allem, was kein Wortzeichen, kein Ziffernzeichen, kein Wagenrücklauf, keine neue Zeile oder kein Doppelpunkt ist.Der Doppelpunkt muss vorhanden sein, um eine Übereinstimmung mit Zeiten zu verhindern, die wie Datumsangaben aussehen (siehe meine Testdaten).

Sie können diesen Teil des Musters optimieren, um den Abgleich zu beschleunigen. Dies ist jedoch eine gute Grundlage, um die meisten gültigen Trennzeichen zu erkennen.

Beachten Sie jedoch;Es wird eine Zeichenfolge mit gemischten Trennzeichen wie dieser 2/12-73 gefunden, bei der es sich möglicherweise nicht um ein gültiges Datum handelt.

Jahreswerte

(\d{4}|\d{2})

Dies entspricht einer Gruppe von zwei oder vier Ziffern. In den meisten Fällen ist dies akzeptabel. Wenn Sie jedoch mit Daten aus den Jahren 0–999 oder darüber hinaus arbeiten, müssen Sie entscheiden, wie damit umgegangen werden soll, da es sich in den meisten Fällen um eine 1, 3 handelt oder >4-stelliges Jahr ist Müll.

Monatswerte

(0?[1-9]|1[0-2])

Entspricht einer beliebigen Zahl zwischen 1 und 12 mit oder ohne führende Null – Hinweis:0 und 00 stimmen nicht überein.

Datumswerte

(0?[1-9]|[12]\d|30|31)

Entspricht einer beliebigen Zahl zwischen 1 und 31 mit oder ohne führende Null – Hinweis:0 und 00 stimmen nicht überein.

Dieser Ausdruck stimmt mit Datums-, Monats- und Jahresformaten überein

(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})

Es stimmt aber auch mit einigen Jahres- und Monatsangaben überein.Es sollte auch mit den Grenzoperatoren verknüpft werden, um sicherzustellen, dass die gesamte Datumszeichenfolge ausgewählt wird und um zu verhindern, dass gültige Unterdaten aus Daten extrahiert werden, die nicht wohlgeformt sind, d. h.ohne Grenzmarkierungen: 20.12.194 entspricht dem 20.12.19 und 101.12.1974 entspricht dem 01.12.1974

Vergleichen Sie die Ergebnisse des nächsten Ausdrucks mit dem obigen mit den Testdaten im Unsinn-Abschnitt (unten).

\b(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})\b

In diesem regulären Ausdruck gibt es keine Validierung, sodass ein wohlgeformtes, aber ungültiges Datum wie der 31.02.2001 abgeglichen wird.Das ist ein Problem mit der Datenqualität, und wie andere bereits gesagt haben, sollte Ihr regulärer Ausdruck die Daten nicht validieren müssen.

Da Sie (als Entwickler) die Qualität der Quelldaten nicht garantieren können, müssen Sie eine zusätzliche Validierung in Ihrem Code durchführen und durchführen, wenn Sie versuchen, eine Übereinstimmung herzustellen Und Die Validierung der Daten im RegEx wird sehr chaotisch und ohne Unterstützung wird es schwierig, sie zu unterstützen sehr prägnante Dokumentation.

Müll rein, Müll raus.

Wenn Sie jedoch gemischte Formate haben, bei denen die Datumswerte variieren, und Sie so viel wie möglich extrahieren müssen;Sie können mehrere Ausdrücke auf diese Weise miteinander kombinieren.

Dieser (katastrophale) Ausdruck stimmt mit DMY- und YMD-Daten überein

(\b(0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](0?[1-9]|1[0-2])[^\w\d\r\n:](\d{4}|\d{2})\b)|(\b(0?[1-9]|1[0-2])[^\w\d\r\n:](0?[1-9]|[12]\d|30|31)[^\w\d\r\n:](\d{4}|\d{2})\b)

ABER Sie können nicht sagen, ob Daten wie der 09.06.1973 der 6. September oder der 9. Juni sind.Mir fällt es schwer, mir ein Szenario vorzustellen, in dem dies nicht irgendwann einmal ein Problem verursachen wird, es eine schlechte Praxis ist und man nicht so damit umgehen sollte – den Dateneigentümer finden und ihn mit dem Governance-Hammer schlagen .

Wenn Sie schließlich eine JJJJMMTT-Zeichenfolge ohne Trennzeichen abgleichen möchten, können Sie einen Teil der Unsicherheit beseitigen und der Ausdruck sieht so aus

\b(\d{4})(0[1-9]|1[0-2])(0[1-9]|[12]\d|30|31)\b

Aber beachten Sie noch einmal, dass es mit wohlgeformten, aber ungültigen Werten wie 20010231 (31. Februar!) übereinstimmt :)

Testdaten

Beim Experimentieren mit den Lösungen in diesem Thread bin ich zu einem Testdatensatz gekommen, der eine Vielzahl gültiger und ungültiger Daten sowie einige knifflige Situationen enthält, in denen Sie möglicherweise eine Übereinstimmung wünschen oder nicht, z. B.Zeiten, die als Datum und Datum in mehreren Zeilen übereinstimmen könnten.

Ich hoffe, das ist für jemanden nützlich.

Valid Dates in various formats

Day, month, year
2/11/73
02/11/1973
2/1/73
02/01/73
31/1/1973
02/1/1973
31.1.2011
31-1-2001
29/2/1973
29/02/1976 
03/06/2010
12/6/90

month, day, year
02/24/1975 
06/19/66 
03.31.1991
2.29.2003
02-29-55
03-13-55
03-13-1955
12\24\1974
12\30\1974
1\31\1974
03/31/2001
01/21/2001
12/13/2001

Match both DMY and MDY
12/12/1978
6/6/78
06/6/1978
6/06/1978

using whitespace as a delimiter

13 11 2001
11 13 2001
11 13 01 
13 11 01
1 1 01
1 1 2001

Year Month Day order
76/02/02
1976/02/29
1976/2/13
76/09/31

YYYYMMDD sortable format
19741213
19750101

Valid dates before Epoch
12/1/10
12/01/660
12/01/00
12/01/0000

Valid date after 2038

01/01/2039
01/01/39

Valid date beyond the year 9999

01/01/10000

Dates with leading or trailing characters

12/31/21/
31/12/1921AD
31/12/1921.10:55
12/10/2016  8:26:00.39
wfuwdf12/11/74iuhwf
fwefew13/11/1974
01/12/1974vdwdfwe
01/01/99werwer
12321301/01/99

Times that look like dates

12:13:56
13:12:01
1:12:01PM
1:12:01 AM

Dates that runs across two lines

1/12/19
74

01/12/19
74/13/1946

31/12/20
08:13

Invalid, corrupted or nonsense dates

0/1/2001
1/0/2001
00/01/2100
01/0/2001
0101/2001
01/131/2001
31/31/2001
101/12/1974
56/56/56
00/00/0000
0/0/1999
12/01/0
12/10/-100
74/2/29
12/32/45
20/12/194

2/12-73

Wartbare Perl 5.10-Version

/
  (?:
      (?<month> (?&mon_29)) [\/] (?<day>(?&day_29))
    | (?<month> (?&mon_30)) [\/] (?<day>(?&day_30))
    | (?<month> (?&mon_31)) [\/] (?<day>(?&day_31))
  )
  [\/]
  (?<year> [0-9]{4})

  (?(DEFINE)
    (?<mon_29> 0?2 )
    (?<mon_30> 0?[469]   | (11) )
    (?<mon_31> 0?[13578] | 1[02] )

    (?<day_29> 0?[1-9] | [1-2]?[0-9] )
    (?<day_30> 0?[1-9] | [1-2]?[0-9] | 30 )
    (?<day_31> 0?[1-9] | [1-2]?[0-9] | 3[01] )
  )
/x

In dieser Version können Sie die Elemente nach Namen abrufen.

say "Month=$+{month} Day=$+{day} Year=$+{year}";

(Es wurde kein Versuch unternommen, die Werte für das Jahr einzuschränken.)

So steuern Sie die Gültigkeit eines Datums im folgenden Format:

JJJJ/MM/TT oder JJJJ-MM-TT

Ich würde Ihnen empfehlen, den folgenden regulären Ausdruck zu verwenden:

(((19|20)([2468][048]|[13579][26]|0[48])|2000)[/-]02[/-]29|((19|20)[0-9]{2}[/-](0[4678]|1[02])[/-](0[1-9]|[12][0-9]|30)|(19|20)[0-9]{2}[/-](0[1359]|11)[/-](0[1-9]|[12][0-9]|3[01])|(19|20)[0-9]{2}[/-]02[/-](0[1-9]|1[0-9]|2[0-8])))

Streichhölzer

2016-02-29 | 2012-04-30 | 2019/09/31

Nichtübereinstimmungen

2016-02-30 | 2012-04-31 | 2019/09/35

Sie können es anpassen, wenn Sie nur „/“- oder „-“-Trennzeichen zulassen möchten.Dieser RegEx kontrolliert streng die Gültigkeit des Datums und überprüft 28, 30 und 31 Tage in Monaten, sogar Schaltjahre mit 29/02-Monaten.

Probieren Sie es aus, es funktioniert sehr gut und schützt Ihren Code vor vielen Fehlern!

Zu Ihrer Information:Ich habe eine Variante für die SQL-Datetime erstellt.Sie finden es dort (suchen Sie nach meinem Namen): Regulärer Ausdruck zur Validierung eines Zeitstempels

Feedback ist willkommen :)

Klingt so, als würden Sie den regulären Ausdruck für diesen Zweck überfordern.Ich würde einen regulären Ausdruck verwenden, um einige Datumsformate abzugleichen, und dann eine separate Funktion verwenden, um die Werte der so extrahierten Datumsfelder zu validieren.

Erweiterte Perl-Version

Beachten Sie die Verwendung von /x Modifikator.

/^(
      (
        ( # 31 day months
            (0[13578])
          | ([13578])
          | (1[02])
        )
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
          | (3[01])
        )
      )
    | (
        ( # 30 day months
            (0[469])
          | ([469])
          | (11)
        )
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
          | (30)
        )
      )
    | ( # 29 day month (Feb)
        (2|02)
        [\/]
        (
            ([1-9])
          | ([0-2][0-9])
        )
      )
    )
    [\/]
    # year
    \d{4}$

  | ^\d{4}$ # year only
/x

Original

^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$

Wenn die obigen Vorschläge bei Ihnen nicht funktioniert haben, verwende ich diesen, da er jedes Datum abruft. Ich habe diesen Ausdruck über 50 Links ausgeführt und er hat alle Daten auf jeder Seite abgerufen.

^20\d\d-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(0[1-9]|[1-2][0-9]|3[01])$ 
    var dtRegex = new RegExp(/[1-9\-]{4}[0-9\-]{2}[0-9\-]{2}/);
    if(dtRegex.test(date) == true){
        var evalDate = date.split('-');
        if(evalDate[0] != '0000' && evalDate[1] != '00' && evalDate[2] != '00'){
            return true;
        }
    }

Dieser reguläre Ausdruck validiert Daten zwischen dem 01.01.2000 und dem 31.12.2099 mit passenden Trennzeichen.

^(0[1-9]|1[012])([- /.])(0[1-9]|[12][0-9]|3[01])\2(19|20)\d\d$

Regex war nicht dazu gedacht, Zahlenbereiche zu validieren (diese Zahl muss zwischen 1 und 5 liegen, wenn die Zahl davor zufällig eine 2 ist und die Zahl davor zufällig unter 6 liegt).Suchen Sie einfach nach dem Muster für die Platzierung von Zahlen in der Regex.Wenn Sie die Eigenschaften eines Datums überprüfen müssen, fügen Sie es in ein Datumsobjekt js/c#/vb ein und fragen Sie dort die Zahlen ab.

Ich weiß, dass dies Ihre Frage nicht beantwortet, aber warum verwenden Sie nicht eine Datumsverarbeitungsroutine, um zu überprüfen, ob es sich um ein gültiges Datum handelt?Selbst wenn Sie den regulären Ausdruck mit einer negativen Lookahead-Behauptung wie (?!31/0?2) ändern (dh nicht mit 31/2 oder 31/02 übereinstimmen), haben Sie immer noch das Problem, 29 02 in Nicht-Schaltjahren zu akzeptieren und über ein einzelnes Trennzeichen-Datumsformat.

Das Problem ist nicht einfach, wenn Sie ein Datum wirklich validieren möchten, überprüfen Sie dies Forenthread.

Ein Beispiel oder eine bessere Möglichkeit in C# finden Sie hier dieser Link

Wenn Sie eine andere Plattform/Sprache verwenden, teilen Sie uns dies mit

Perl 6-Version

Nachdem Sie dies verwendet haben, um die Eingabe zu überprüfen, in der die Werte verfügbar sind $/ oder einzeln als $<month>, $<day>, $<year>.(Das ist nur die Syntax für den Zugriff auf Werte in $/ )

Es wurde kein Versuch unternommen, das Jahr zu überprüfen oder sicherzustellen, dass es in Nicht-Schaltjahren nicht mit dem 29. Februar übereinstimmt.

Wenn Sie darauf bestehen, dies mit einem regulären Ausdruck zu tun, würde ich etwas empfehlen wie:

( (0?1|0?3| <...> |10|11|12) / (0?1| <...> |30|31) |
  0?2 / (0?1| <...> |28|29) ) 
/ (19|20)[0-9]{2}

Das könnte ermöglichen das Lesen und Verstehen.

Ein etwas anderer Ansatz, der für Sie nützlich sein kann oder auch nicht.

Ich bin in PHP.

Das Projekt, auf das es sich bezieht, wird niemals ein Datum vor dem 1. Januar 2008 haben.Also nehme ich das eingegebene „Datum“ und verwende strtotime().Wenn die Antwort >= 1199167200 ist, dann habe ich ein Datum, das für mich nützlich ist.Wenn etwas eingegeben wird, das nicht wie ein Datum aussieht, wird -1 zurückgegeben.Wenn Null eingegeben wird, wird die aktuelle Datumsnummer zurückgegeben. Daher müssen Sie zunächst prüfen, ob ein Eintrag ungleich Null vorliegt.

Funktioniert für meine Situation, vielleicht auch für deine?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top