Wyrażenie regularne - wyłuskanie dat

0

Witam,

analizuję zadanie, które przy podaniu ciągu znaków:

2007-01-12Jakis txt2008-01-31 xxx 2008-02-29 2008-15-10 2008-19-45 2009-05-01
20999-11-11 pppp 2001-00-01 09-01-01 2001-01-00 2009-01-111 2009-02-29 1998-11-11

powinno zwrócić jedynie prawidłowe daty tj.
2007-01-12 2008-01-31 2008-02-29 2009-05-01 1998-11-11

Wzorzec jest następujący:
Pattern pattern = Pattern.compile("[1-9]\d{3}-\d{2}-\d{2}");

Zwraca:
2007-01-12 2008-01-31 2008-02-29 2009-05-01 2009-01-11 1998-11-11

Problem mam z podkreśloną datą 2009-01-111, która została zgarnięta jako 2009-01-11.

Jestem początkujący i nie mogę zrozumieć dlaczego ciąg 20999-11-11 został ominięty (słusznie) a 2009-01-111 już nie.

Będę wdzięczny za wyjaśnienie.

Pozdrawiam,
Arek

0

Bo fragment 2009-01-111 nie zawiera prawidłowej daty, a ciąg 2009-01-111 ją zawiera.

1

Sprawdź sobie tutaj:
http://regexr.com/3dig5

0

Ok, ale jak zmienić wzór aby 2009-01-111 też się nie załapało?

0

dodaj if że jak następny znak też jest liczbą to żeby uznał że to nie data

0

Jak w praktyce miałoby to wyglądać?

0

może [1-9]\d{3}-\d{2}-\d{2,} i wyniki potem w pętli odfiltrować: te które mają 10 znaków zostają, powyżej wyrzucasz.

0

Czyli rozumiem, że przy pomocy samych wyrażeń regularnych (podanego schematu) nie da się tego rozwiązać?

2

Da się bo java ma rozszerzone wyrażenia regularne i wspiera negative lookahead.
[1-9]\\d{3}-\\d{2}-\\d{2}(?!\\d+)

Ten: (?!\\d+) fragment oznacza że parser ma sprawdzić czy na pewno dalszy fragment nie jest liczbą

0
Shalom napisał(a):

Da się bo java ma rozszerzone wyrażenia regularne i wspiera negative lookahead.
[1-9]\\d{3}-\\d{2}-\\d{2}(?!\\d+)

Ten: (?!\\d+) fragment oznacza że parser ma sprawdzić czy na pewno dalszy fragment nie jest liczbą

Widzę, że w Javie są rzeczy, o "których się nawet nie śniło filozofom".
A przynajmniej mi:)

Bardzo dziękuję.

0

co oznaczają \ w tym wzorcu

0

bo rozumiem że - jest po prostu myślnikiem w dacie

0

To wyrażenie i tak nie obejmuje wszystkich przypadków - dopuszcza nieprawidłowe daty. Założę się, że Java ma jakieś dedykowane metody do parsowania dat - wtedy pewnie można by było zrobić splita po spacjach i przetestować każdy podciąg w pętli bez zabawy w wyrażenia regularne.

0

pewnie ma ale jakie ?? :)

1

@hebel, np takie

        String input = "2007-01-12Jakis txt2008-01-31 xxx 2008-02-29 2008-15-10 2008-19-45 2009-05-01\n 20999-11-11 pppp 2001-00-01 09-01-01 2001-01-00 2009-01-111 2009-02-29 1998-11-11";
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        formatter.setLenient(false);
        int index = 0;
        Date date = null;

        ParsePosition pos = new ParsePosition(0);
        while(index < input.length())
        {
            while(index < input.length() && !Character.isDigit(input.charAt(index)))
            {
                index++;
            }
            pos = new ParsePosition(index);
            date = formatter.parse(input,pos);
            if(date != null)
            {
                System.out.println(formatter.format(date));
                index = pos.getIndex();
            }
            else
            {
                index = pos.getIndex() + 1;
            }
        }
0

Cześć,

Twój kod wyprowadza na konosolę daty:
2007-01-12 2008-01-31 2008-02-29 2009-05-01 20999-11-11 0009-01-01 1998-11-11

Jak go ulepszyć by wyprowadzał w pełni poprawne daty?
Te dwie daty nie są poprawne: 20999-11-11 0009-01-01

Dzięki, pozdrawiam,

0

Z jakiego powodu daty "20999-11-11" i "0009-01-01" są niepoprawne? W roku 20999 nie będzie listopada?

0

W roku 20999 niczego już nie będzie ;)

Załóżmy, że Lata mają być reprezentowane przez 4 cyfrowe ciągi. Jakbyś to wtedy ujął w kodzie?
Teraz zauważyłem też, że twój program poprawił datę 09-01-01 na 0009-01-01. A gdyby program miał nie poprawiać domyślnych błędów w datach tylko eliminować daty o błędnych formatach?

0

A jaki domyślny błąd mój program poprawił? On wypisał tylko daty o prawidłowych formatach. Jeśli uznajesz pewne daty za niepoprawne, to musisz do kod wprowadzić kryterium poprawności, np. tak:

            if(date != null)
            {
                Calendar calendar = new GregorianCalendar();
                calendar.setTime(date);
                int year = calendar.get(Calendar.YEAR);
                if(year >= 1000 && year <= 9999)
                {
                    System.out.println(parser.format(date));
                }
                index = pos.getIndex();
            }
0

Rozwiązanie dla enginów nie tylko Javovych: ([1-9]\d{3}-\d{2}-\d{2})[^0-9]
(trzeba użyć grupy 1 jako wyniku).
https://regex101.com/r/uP2gC9/2

Przy czym jak napisano wcześniej - trzeba by jeszcze weryfikować wartości wewnatrz daty - co też się da zrobić regexpem (ale to będzie trochę dłuższy regexp).

https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html

1 użytkowników online, w tym zalogowanych: 0, gości: 1