RegEx a dátumminta illesztéséhez a Java-ban
1. Bemutatkozás
A rendszeres kifejezések hatékony eszköz a különféle minták megfelelő illesztésére, ha azokat megfelelően használják.
Ebben a cikkben felhasználjuk java.util.regex csomagot annak meghatározásához, hogy adott-e Húr érvényes dátumot tartalmaz, vagy sem.
A reguláris kifejezések bemutatásához olvassa el az Útmutató a Java rendszeres kifejezések API-hoz című útmutatónkat.
2. A dátumformátum áttekintése
Meg fogunk határozni egy érvényes dátumot a nemzetközi Gergely-naptárhoz viszonyítva. Formátumunk az általános mintát követi: ÉÉÉÉ-HH-NN.
Vegyük bele az a fogalmát is Ugrás év, azaz február 29. napját tartalmazó év. A Gergely-naptár szerint egy évet hívunk Ugrás ha az évszámot egyenletesen el lehet osztani 4 kivéve azokat, amelyek oszthatók 100 de beleértve azokat is, amelyek oszthatók 400.
Minden más esetben, egy évet hívunk szabályos.
Példák az érvényes dátumokra:
- 2017-12-31
- 2020-02-29
- 2400-02-29
Példák érvénytelen dátumokra:
- 2017/12/31: helytelen token elválasztó
- 2018-1-1: hiányzó vezető nullák
- 2018-04-31: rossz napok számítanak áprilisra
- 2100-02-29: ez az év nem ugrik be, mivel az érték osztódik 100, tehát február 28 napra korlátozódik
3. Megoldás megvalósítása
Mivel a dátumot szabályos kifejezésekkel fogjuk egyeztetni, először vázoljuk fel a kezelőfelületet DateMatcher, amely egyetlen mérkőzések módszer:
nyilvános felület DateMatcher {logikai egyezések (Karakterlánc dátuma); }
Az alábbiakban lépésről lépésre bemutatjuk a megvalósítást, a végén a teljes megoldás felé építve.
3.1. A széles formátumnak megfelelő
Kezdjük egy nagyon egyszerű prototípus létrehozásával, amely kezeli a páros formátumkorlátjait:
class FormattedDateMatcher implementálja a DateMatcher {private static Pattern DATE_PATTERN = Pattern.compile ("^ \ d {4} - \ d {2} - \ d {2} $"); @ Nyilvános logikai egyezések felülírása (karakterlánc dátuma) {return DATE_PATTERN.matcher (dátum) .matches (); }}
Itt ezt meghatározzuk az érvényes dátumnak három egész számcsoportból kell állnia, amelyek elválasztva kötőjellel vannak elválasztva. Az első csoport négy egész számból áll, a fennmaradó két csoportban két-két egész szám van.
Megfelelő dátumok: 2017-12-31, 2018-01-31, 0000-00-00, 1029-99-72
Nem egyező dátumok: 2018-01, 2018-01-XX, 2020/02/29
3.2. Megfelelő dátumformátum
Második példánk elfogadja a dátumjelek tartományait, valamint a formázási kényszerünket. Az egyszerűség kedvéért érdeklődésünket az 1900–2999 évekre korlátoztuk.
Most, hogy sikeresen megfeleltünk általános dátumformátumunknak, ezt tovább kell korlátoznunk - annak érdekében, hogy megbizonyosodjunk a dátumok tényleges helyességéről:
^((19|2[0-9])[0-9]{2})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$
Itt hármat mutattunk be csoportok egész számtartományoknak, amelyeknek meg kell egyezniük:
(19|2[0-9])[0-9]{2}
korlátozott évekre terjed ki azzal, hogy egy számmal kezdődik 19 vagy 2X utána néhány számjegy.0[1-9]|1[012]
havi számnak felel meg 01-120[1-9]|[12][0-9]|3[01]
egy napszámot megad egy tartományban 01-31
Megfelelő dátumok: 1900-01-01, 2205-02-31, 2999-12-31
Nem egyező dátumok: 1899-12-31, 2018-05-35, 2018-13-05, 3000-01-01, 2018-01-XX
3.3. Megfelel a február 29-nek
A szökőévek megfelelő illesztése érdekében először is meg kell tennünk azonosítsa, amikor szökőévvel találkoztunk, majd győződjön meg arról, hogy elfogadjuk-e február 29-ét érvényes dátumként ezekre az évekre.
Mivel a szökőévek száma korlátozott tartományunkban elég nagy, a megfelelő oszthatósági szabályokat kell alkalmaznunk a szűréshez:
- Ha a szám utolsó két számjegye által alkotott szám osztható 4-gyel, az eredeti szám osztható 4-gyel
- Ha a szám utolsó két számjegye 00, akkor a szám osztható 100-mal
Itt van egy megoldás:
^((2000|2400|2800|(19|2[0-9](0[48]|[2468][048]|[13579][26])))-02-29)$
A minta a következő részekből áll:
2000|2400|2800
szökőév halmazához illeszkedik 400 korlátozott tartományban 1900-299919|2[0-9](0[48]|[2468][048]|[13579][26]))
egyezik mindennel fehér lista évek kombinációi, amelyeknek osztója van 4 és ne legyen elválasztója 100-02-29
mérkőzések Február 2-án
Megfelelő dátumok: 2020-02-29, 2024-02-29, 2400-02-29
Nem egyező dátumok: 2019-02-29, 2100-02-29, 3200-02-29, 2020/02/29
3.4. Megfelelő általános februári napok
Amellett, hogy a szökő években megegyezik február 29-én, ráadásul minden évben meg kell egyeznünk a február összes többi napját (1 - 28):
^(((19|2[0-9])[0-9]{2})-02-(0[1-9]|1[0-9]|2[0-8]))$
Megfelelő dátumok: 2018-02-01, 2019-02-13, 2020-02-25
Nem egyező dátumok: 2000-02-30, 2400-02-62, 2018/02/28
3.5. 31 napos hónapok egyeztetése
A január, március, május, július, augusztus, október és december hónapoknak 1 és 31 nap között kell lenniük:
^(((19|2[0-9])[0-9]{2})-(0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01]))$
Megfelelő dátumok: 2018-01-31, 2021-07-31, 2022-08-31
Nem egyező dátumok: 2018-01-32, 2019-03-64, 2018/01/31
3.6. 30 napos hónapok egyeztetése
Az április, június, szeptember és november hónapoknak 1 és 30 nap között kell lenniük:
^(((19|2[0-9])[0-9]{2})-(0[469]|11)-(0[1-9]|[12][0-9]|30))$
Megfelelő dátumok: 2018-04-30, 2019-06-30, 2020-09-30
Nem egyező dátumok: 2018-04-31, 2019-06-31, 2018/04/30
3.7. Gergely-dátum-egyező
Most már tehetjük kombinálja a fenti mintákat egyetlen egyezőbe, hogy teljes legyen GregorianDateMatcher kielégítve az összes korlátot:
class GregorianDateMatcher implementálja a DateMatcher {private static Pattern DATE_PATTERN = Pattern.compile ("^ ((2000 | 2400 | 2800 | (19 | 2 [0-9] (0 [48] | [2468] [048] | [13579] [ 26]))) - 02-29) $ "+" | ^ (((19 | 2 [0-9]) [0-9] {2}) - 02- (0 [1-9] | 1 [ 0-9] | 2 [0-8])) $ "+" | ^ (((19 | 2 [0-9]) [0-9] {2}) - (0 [13578] | 10 | 12 ) - (0 [1-9] | [12] [0-9] | 3 [01])) $ "+" | ^ (((19 | 2 [0-9]) [0-9] {2 }) - (0 [469] | 11) - (0 [1-9] | [12] [0-9] | 30)) $ "); @ Nyilvános logikai egyezések felülírása (karakterlánc dátuma) {return DATE_PATTERN.matcher (dátum) .matches (); }}
Használtunk egy váltakozás karakter „|” hogy legalább egynek megfeleljen a négy ág közül. Tehát a február érvényes dátuma egybeesik a szökőév február 29. első ágával, vagy bármely nap második ágával. 1 nak nek 28. A hátralévő hónapok dátumai egyeznek a harmadik és a negyedik ággal.
Mivel nem optimalizáltuk ezt a mintát a jobb olvashatóság érdekében, nyugodtan kísérletezzen a hosszával.
Ebben a pillanatban kielégítettük az összes korlátozást, amelyeket az elején bevezettünk.
3.8. Megjegyzés a teljesítményről
Az összetett reguláris kifejezések elemzése jelentősen befolyásolhatja a végrehajtási folyamat teljesítményét. A cikk elsődleges célja nem az volt, hogy megtanuljon egy hatékony módszert tesztelni egy húr tagságát az összes lehetséges dátumban.
Fontolja meg a LocalDate.parse () a Java8 biztosítja, ha megbízható és gyors megközelítésre van szükség a dátum érvényesítéséhez.
4. Következtetés
Ebben a cikkben megtanultuk, hogyan használjuk a reguláris kifejezéseket a Gergely-naptár szigorúan formázott dátumának összehangolásához, megadva a formátum, a tartomány és a hónapok hosszának szabályait is.
Az ebben a cikkben bemutatott összes kód elérhető a Github oldalon. Ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.