REGEX dla daty + czasu - gdzie mam błąd?

REGEX dla daty + czasu - gdzie mam błąd?
bambosze_babuni
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 7 lat
  • Postów:5
0

Potrzebuję sprawdzić, czy wpisana przez użytkowanika wartość mieści się w formacie:

yyyy-MM-dd hh:mm:ss
(chciałbym, żeby np. 2015-3-2 23:1:1 albo 2015-03-02 23:01:01 również było poprawną formą)

Do tego celu napisałem następujący kod:

Kopiuj
std::string strDateTimeRegex = 
"^(19[0-9][0-9]|20[0-9][0-9])-([1-9]|0[1-9]|1[012])-([1-9]|0[1-9]|[12][0-9]|3[01])\s([1-9]|[01][1-9]|2[1-3]):([1-9]|[0-5][1-9]):([1-9]|[0-5][1-9])$";

	std::regex oREPattern(strDateTimeRegex);
	bool bMatch = std::regex_match(*a_pstrInput, oREPattern);

	std::cout << *a_pstrInput << " -- " << (bMatch ? "Valid" : "Invalid") << std::endl;

a_pstrInput to oczywiście wartość wpisywana przez użytkownika.

Czemu ciągle mam "Invalid"?
Czy jakiś dobry człowiek może mi wskazać, co robię źle?
Bo pierwszy raz mam bawię się regular expressions i na bank robię coś źle... Ale co?

IM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:46
1

Jezu, ale syf. Weź po prostu najpierw splitnij string wejściowy po spacjach. Zvaliduj pierwszą część: i.e. datę. Potem zvaliduj godzinę i będzie. Nie rób takich gównianych regexpow na miliard znaków, o to jest nieczytelne i efektywnie jest bez sensu.

bambosze_babuni
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 7 lat
  • Postów:5
0
IForgotMyPass napisał(a):

Jezu, ale syf. Weź po prostu najpierw splitnij string wejściowy po spacjach. Zvaliduj pierwszą część: i.e. datę. Potem zvaliduj godzinę i będzie. Nie rób takich gównianych regexpow na miliard znaków, o to jest nieczytelne i efektywnie jest bez sensu.

Ja rozumiem, że to nie jest piękne, ale myślałem, że się przy okazji nauczę czegoś nowego i dowiem, gdzie robię błąd. Nie chce parsować stringów, bo się nie dowiem nic nowego i zajmie to milion linijek.

IM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:46
0

No ale to ziomek, masz stringi postaci "x-y-z u-v-w" (czy jakoś tak) to podziel je najpierw po spacji, potem podziel je po znaku '-' a potem validuj osobno (jesli chcesz to regexpami) i będzie prościej.

Im mniejszy problem tym łatwiej go rozwiązać. Dziel i zwyciężaj ;-)

edytowany 2x, ostatnio: IForgotMyPass
bambosze_babuni
  • Rejestracja:prawie 10 lat
  • Ostatnio:ponad 7 lat
  • Postów:5
0

Ostatecznie stanęło na dwóch regexach:

Kopiuj
//regex pattern for date
string strDateRegex =
		"^(19[0-9][0-9]|20[0-9][0-9])"		//year
		"-"
		"([1-9]|0[1-9]|1[012])"				//month
		"-"
		"([1-9]|0[1-9]|[12][0-9]|3[01])$";		//day
//regex pattern for time
string strTimeRegex =
		"^([1-9]|[01][1-9]|2[1-3])"			//hours
		":"
		"([1-9]|[0-5][1-9])"				//minutes
		":"
		"([1-9]|[0-5][1-9])$";				//seconds

Coś był problem ze spacją (\s). Ale dzięki za pomoc ;)

MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:minuta
1

Ja wiem, że Regexpy są fajne, ale przecież to jest jeden z tych przypadków, gdzie się nie powinno ich stosować!
Masz jakąś funkcję do parsowania daty (konwersji stringa na konkretą wartość), użyj tej metody i sprawdzaj czy konwersja wykonała się poprawnie.
Zalety rezygnacji z regexpa w tym miejscu

  • będzie działąc szybciej
  • będzie bardziej zrozumiałe
  • będzie obsługiwać różne lokalizację bez najmniejszego wysiłku
  • nie trzeba będzie rozszyfrowywać regexpa jak do tego będziesz wracał
  • kodu będzie mniej

http://www.cplusplus.com/reference/iomanip/get_time/
http://www.cplusplus.com/reference/ctime/strftime/


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22
RE
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:około rok
0

Nie powinieneś w wyrażeniu regularnym sprawdzać poprawnej logiki (semantyki) takich wyrażeń (z tego twojego sprawdzania wychodzi póki co to, że za poprawną datę przejdzie 31. lutego). Jeżeli chcesz zostać przy regexpach to skróć go do formy "liczba-liczba-liczba liczba:liczba:liczba" i resztę sprawdź normalnymi warunkami (co swoją drogą też nie jest trywialne i mało która biblioteka od dat oraz kalendarzy robi to porządnie, włączając w to domyślne implementacje dat w Javie i .NET).

edytowany 1x, ostatnio: Rev
0
Rev napisał(a):

Nie powinieneś w wyrażeniu regularnym sprawdzać poprawnej logiki (semantyki) takich wyrażeń (z tego twojego sprawdzania wychodzi póki co to, że za poprawną datę przejdzie 31. lutego). Jeżeli chcesz zostać przy regexpach to skróć go do formy "liczba-liczba-liczba liczba:liczba:liczba" i resztę sprawdź normalnymi warunkami

Założenie było takie, żeby było sprawdzenie, o którym wspominasz: liczba-liczba-liczba liczba:liczba:liczba (plus, żeby nie było kwiatków w stylu 2015-13-32 25:61:81). Takie przypadki jak 31. lutego sprawdzam już później.

MarekR22 napisał(a):

Zalety rezygnacji z regexpa w tym miejscu

  • będzie działąc szybciej
  • będzie bardziej zrozumiałe
  • będzie obsługiwać różne lokalizację bez najmniejszego wysiłku
  • nie trzeba będzie rozszyfrowywać regexpa jak do tego będziesz wracał
  • kodu będzie mniej/

No i to jest wartościowa informacja! Dziękuję!

W ogóle to przekonaliście mnie, żebym następnym razem odpuścił sobie takie regexpy :)

MO
Wiesz, tak nie skreślaj regexpów w każdym przypadku... Kolega MarekR22 w tym przypadku radzi dobrze ale przy innych regexpy są ok. Jak masz tzw. "brudne dane na wejściu" czasem się po prostu nie da sensowniej/inaczej niż regexp :) Tu jednak danych brudnych nie ma a sprawdzenie poprawności wymaga narzędzi poza regexp.
bambosze_babuni
@Mokrowski Nie, nie, skreślać to nie, ale tutaj z tym regexem to chyba wytoczyłem armatę na komara ;) Dziękuję za komentarz!
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:minuta
0

Moja rada jest taka, jeśli wpisujesz w kod twardo wyrażenie regularne, to w 90% wypadków należy zrobić to kodem.
Regexp jest bardzo dobry jako opcja konfiguracyjna, albo jako dana wejściowa od bardziej rozgarniętego użytkownika.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
bambosze_babuni
@MarekR22 Co masz na myśli w tym przypadku mówiąc "wpisać twardo" i że "należy zrobić to kodem"? Bo nie wiem, czy dobrze Cię rozumiem...
MarekR22
wpisywać coś twardo w kod znaczy, że wyrażenie regularne jest stałą lub literałem w kodzie i nie ulega zmianie. A zrobić kodem czyli nie używać regexp, ale np użyć get_time.
RE
Moderator
  • Rejestracja:około 18 lat
  • Ostatnio:około rok
0

@MarekR22, możesz wyjaśnić?

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.