Regex, aby dopasować cyfrę dwa lub cztery razy

95

To proste pytanie dotyczące wyrażeń regularnych, ale nie znajduję odpowiedzi.

Chcę ustalić, czy liczba pojawia się w sekwencji dokładnie dwa lub cztery razy. Jakiej składni mogę użyć?

\d{what goes here?}

Próbowałem \d{2,4}, ale to wyrażenie akceptuje również trzy cyfry.

Renato Dinhani
źródło
1
Na przykład, aby dopasować się dwu- lub czterocyfrowy rok .
DavidRR
Co chcesz, aby ciąg znaków if był abc 123 xyz? Czy powinien pasować, 12ponieważ to dokładnie dwie cyfry w kolejności? A może nie, ponieważ 12jest częścią większej sekwencji cyfr, 123która sama w sobie nie ma ani 2, ani 4 długości? Gdybym miał zgadywać, pomyślałbym, że chcesz tego drugiego zachowania, ale nie wynika to jasno z twojego pytania. Pomocne byłyby przykłady i / lub jaśniejsza specyfikacja. To samo pytanie do abc 12345 def... co powinno się tam stać?
Jean-François Corbett

Odpowiedzi:

146

Nie ma określonej składni, ale można to zrobić na wiele sposobów:

(?:\d{4}|\d{2})    <-- alternation: four digits or two
\d{2}(?:\d{2})?    <-- two digits, and optionally two more
(?:\d{2}){1,2}     <-- two digits, times one or two
ruakh
źródło
1
Osobiście pomyślałem tylko o \d{2}(?:\d{2})?rozwiązaniu od razu - niezła różnorodność tych - w szczególności ostatnie, które wydaje się bardzo ładne i skalowalne.
Nightfirecat
3
+1 za zwracanie uwagi na kolejność potrzebną podczas używania naprzemiennego dopasowania najpierw 4 cyfry, a następnie 2 cyfry. Dobra robota również przy innych odmianach.
Ahmad Mageed
9
Dla każdego, kto, tak jak ja, nie rozumiał użycia (?:tego, rozpoczyna „grupę nieprzechwytującą” (grupę, do której nie należy odwoływać się w instrukcji zamiany). Możesz też po prostu użyć parenów, ale utworzą one grupę przechwytywania. Więcej szczegółów tutaj: stackoverflow.com/questions/3512471/non-capturing-group
Jeremy Moritz
Pokażą one ten sam wynik dla „333” i „33”
Dan
1
@Dan: Te wyrażenia regularne nie pasują do pełnego ciągu "333". Możliwe, że przez pomyłkę używasz funkcji „znajdź pasujący podciąg” z biblioteki wyrażeń regularnych zamiast funkcji „sprawdź, czy cały ciąg pasuje”. Powinieneś zapoznać się z jego dokumentacją.
ruakh
3
(?<!\d)(\d{2}|\d{4})(?!\d)

To jest właściwy sposób, aby to zrobić. Przyjęta odpowiedź jest błędna.

Dopasowałoby 3 cyfry (lub 5). Więc to jest złe w moich oczach .

1) Sprawdź, czy nie ma cyfry przed sekwencją 2 lub 4 cyfr lub po sekwencji dwóch lub czterech cyfr.

  • (<!) składnia jest ujemna lookbehind

  • (?!) składnia jest ujemnym wyprzedzeniem.

Powyższe działałoby dla środkowego ciągu:

Jeśli wyszukiwanie ciąg nie ma treści wokół niego można używać ^i $rozpocząć i zakończyć kotew strunowych:

^\d{4}$|^\d{2}$
JGFMK
źródło
1
Nie powiedziałbym, że przyjęta odpowiedź jest błędna. Powiedziałbym, że pytanie jest niejasne i że ta odpowiedź dotyczy jednej ważnej jego interpretacji. Twoja odpowiedź dotyczy innej ważnej interpretacji (która, jak sądzę, jest bardziej prawdopodobna - ale najwyraźniej pytający nie ...).
Jean-François Corbett
2
„Dopasowałoby 3 cyfry” nie jest całkiem dokładne. Myślę, że masz na myśli „To pasowałoby do dwucyfrowego podciągu z trzycyfrowej sekwencji”.
Jean-François Corbett
1
Twoja odpowiedź nie działa tak, jak powinna w przypadku sekwencji składających się z 5 lub więcej cyfr . Nie jestem ekspertem od regexów, ale wydaje mi się, że jednym ze sposobów rozwiązania tego problemu jest zastosowanie ujemnego wyprzedzenia w przód / w tył w obu przypadkach (sekwencje 2- i 4-cyfrowe):(?<!\d)(\d{2}|\d{4})(?!\d)
Jean-François Corbett
Myślę, że masz rację co do 5 cyfr. Dzięki za korektę. Naprawię to.
JGFMK
^\d{4}$|^\d{2}$byłby potencjalnym sposobem rozwiązania tego problemu. Jakby^\d{2}(?!\d)|^\d{4}(?!\d)
JGFMK