Dlaczego zakres [01-12] nie działa zgodnie z oczekiwaniami?


93

Próbuję użyć wzorca zakresu [01-12]w wyrażeniu regularnym, aby dopasować dwucyfrowe mm, ale to nie działa zgodnie z oczekiwaniami.


9
Dopasowujesz znaki , a nie sekwencje znaków . Zasadniczo dopasowujesz przeciw 0, 1 do 1 i 2 (tj. 0, 1 i 2). Rozważ to:, to [a-z0-9]dopasowuje wszystkie małe litery i wszystkie cyfry, ale tylko jako pojedynczy znak.
Lasse V. Karlsen

fwiw Stworzyłem narzędzie javascript, które tworzy wysoce zoptymalizowane wyrażenie regularne z dwóch danych wejściowych (min / max) github.com/jonschlinkert/to-regex-range
jonschlinkert

0 [1-9] | 1 [0-2] -> 0 | 1 | 2 -> [] sw wyrażeniu regularnym oznacza klasę znaków. Jeśli nie określono zakresów, niejawnie lub każdy znak.
Badri Gs

Czy musisz dopasować go do czystego wyrażenia regularnego? Jeśli nie, możesz: 1.) po prostu użyć \d+wzorca, 2.) przekonwertować pasujące łańcuchy na liczby w swoim kodzie. a następnie 3.) sprawdź zakres liczb, na przykład if(num >= 0 && num <= 12){ /*do something*/ }. Jest o wiele szybszy i elastyczny.
acegs

Odpowiedzi:


197

Wydaje się, że źle zrozumiałeś, jak działa definicja klas znaków w wyrażeniu regularnym.

Pasują do każdej ze strun 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, lub 12, coś jak to działa:

0[1-9]|1[0-2]

Bibliografia


Wyjaśnienie

Klasa znaków sama próbuje dopasować jeden i dokładnie jeden znak z ciągu wejściowego. [01-12]faktycznie definiuje [012], klasę znaku, który odpowiada jeden znak z wejścia przed każdym z 3 znaków 0, 1lub 2.

-Definicja zakres idzie od 1celu 1, która obejmuje tylko 1. Z drugiej strony, coś [1-9]zawiera 1, 2, 3, 4, 5, 6, 7, 8, 9.

Początkujący często popełniają błędy, definiując takie rzeczy jak [this|that]. To nie „działa”. Postać ta definiuje definicji [this|a], tj dopasowuje jeden znak z wejścia przeciwko któremukolwiek z 6 znaków t, h, i, s, |lub a. Bardziej niż prawdopodobne (this|that)jest to, co jest zamierzone.

Bibliografia


Jak definiowane są zakresy

Jest więc teraz oczywiste, że wzór taki jak between [24-48] hoursnie „działa”. Klasa znaków w tym przypadku jest równoważna [248].

Oznacza to, że -w definicji klasy znaków nie definiuje się zakresu liczbowego we wzorcu. Silniki Regex tak naprawdę nie „rozumieją” liczb we wzorcu, z wyjątkiem składni skończonych powtórzeń (np. a{3,5}Dopasowania między 3 a 5 a).

Definicja zakresu zamiast tego wykorzystuje kodowanie znaków ASCII / Unicode do definiowania zakresów. Znak 0jest kodowany w ASCII jako 48 dziesiętny; 9wynosi 57. Zatem definicja znaku [0-9]obejmuje wszystkie znaki, których wartości w kodowaniu mieszczą się w przedziale od 48 do 57 dziesiętnych. Raczej rozsądnie, przez projekt są to znaki 0, 1, ..., 9.

Zobacz też


Inny przykład: od A do Z

Rzućmy okiem na inną powszechną definicję klasy znaków [a-zA-Z]

W ASCII:

  • A= 65, Z= 90
  • a= 97, z= 122

To znaczy że:

  • [a-zA-Z]i [A-Za-z]są równoważne
  • W większości smaków [a-Z]prawdopodobnie będzie to niedozwolony zakres znaków
    • ponieważ a(97) jest „większe niż” niż Z(90)
  • [A-z] jest legalne, ale zawiera również te sześć znaków:
    • [(91), \(92), ](93), ^(94), _(95), `(96)

Powiązane pytania


Dla mnie szukałem miesięcy bez przedrostka 0, jeśli jest jednocyfrowa. Użyłem tego ([1-9] | (1 [0-2])) i działa.
bunjeeb

3
Ważna uwaga: jeśli znajdziesz na tej stronie rozwiązanie dla zakresu numerów, które ma tylko pojedyncze cyfry przed przejściem do dziesiątek, 0[1-9]|1[0-2]nie zadziała. Zmieniając go do logicznego kolejnego kroku [1-9]|1[0-2]nie działa albo ze zrozumiałych względów (dopasowuje 1tylko 10, 11i 12). Musiałem użyć, \b(?:[0-9]|1[0-1])\baby temu zapobiec. \bupewnia się, że wyrażenie regularne pasuje do granic słowa (lub w tym przypadku liczby) ( ^& $nie); nawiasy powodują, że lub ( |) rozważają drugą stronę; a na koniec ?:nie należy tworzyć przedłożenia za pomocą nawiasów.
user66001

@polygenelubricants: "1,2,3,4,5,6,7,8,9,10,17,18".match(/^(([1-9]|1[0-7])\,?)+$/g )Czy możesz mi powiedzieć, dlaczego to wyrażenie regularne JS jest zgodne z wartością powyżej 17?
edam

@edam - polygenelubricants mogłyby i tak mógłbym, ale wtedy bylibyśmy odpowiadając na questi ... Czekaj ... czy to jest pytanie prosicie w komentarzu ? Na tej stronie jest rulez ;) Zadaj pytanie, jeśli masz nowe pytanie. Komentarze służą wyłącznie do krytykowania i proszenia o wyjaśnienia oraz do odpowiadania na nie.
robinCTS

1
@edam Och, rozumiem. Państwo nie re-poprosić go jako pytanie o godzinę później. To wspaniale! Jednak prawdopodobnie dobrym pomysłem byłoby usunięcie tutaj swojego komentarza.
robinCTS

24

Klasa znaków w wyrażeniach regularnych, oznaczona [...]składnią, określa reguły dopasowania pojedynczego znaku na wejściu. W związku z tym wszystko, co piszesz w nawiasach, określa, jak dopasować pojedynczy znak .

Twój wzór [01-12]jest zatem podzielony w następujący sposób:

  • 0 - dopasuj pojedynczą cyfrę 0
  • lub 1-1, dopasuj pojedynczą cyfrę z zakresu od 1 do 1
  • lub 2, dopasuj pojedynczą cyfrę 2

Więc w zasadzie wszystko, co dopasowujesz, to 0, 1 lub 2.

Aby przeprowadzić dopasowanie, które chcesz, dopasowując dwie cyfry z zakresu od 01 do 12 jako liczby, musisz pomyśleć o tym, jak będą wyglądać jako tekst.

Ty masz:

  • 01-09 (tj. Pierwsza cyfra to 0, druga cyfra to 1-9)
  • 10-12 (tj. Pierwsza cyfra to 1, druga cyfra to 0-2)

Będziesz musiał wtedy napisać wyrażenie regularne, które może wyglądać następująco:

  +-- a 0 followed by 1-9
  |
  |      +-- a 1 followed by 0-2
  |      |
<-+--> <-+-->
0[1-9]|1[0-2]
      ^
      |
      +-- vertical bar, this roughly means "OR" in this context

Zwróć uwagę, że próba połączenia ich w celu uzyskania krótszego wyrażenia zakończy się niepowodzeniem, podając fałszywie dodatnie dopasowania dla nieprawidłowych danych wejściowych.

Na przykład wzór [0-1][0-9]będzie w zasadzie pasował do liczb 00-19, czyli trochę więcej niż chcesz.

Próbowałem znaleźć konkretne źródło, aby uzyskać więcej informacji na temat klas znaków, ale na razie wszystko, co mogę ci podać, to zapytanie Google dotyczące klas znaków Regex . Miejmy nadzieję, że znajdziesz tam więcej informacji, które mogą Ci pomóc.


9

Działa to również:

^([1-9]|[0-1][0-2])$

[1-9] dopasowuje pojedyncze cyfry od 1 do 9

[0-1][0-2] dopasowuje dwucyfrowe cyfry od 10 do 12

Istnieje kilka przykładów dobrych tutaj


2
Aby być dokładnym, [0-1][0-2]również pasuje 00. To powiedziawszy, +1 dla linku (którego użyłem w mojej odpowiedzi).
poligenelubricants

2
[0-1][0-2]musi być dokładnie zinterpretowany, ponieważ zezwala na ciągi takie jak 00, 01i 02, ale nie przyznaje 03się do 09, przyznając ostatecznie 10, 11i 12. Prawidłowe wyrażenie regularne do tego jest [1-9]|1[0-2]lub nawet 0*([1-9]|1[0-2])(ostatnie zezwala na dowolną liczbę zer wiodących).
Luis Colorado

1

W []ów w regex oznaczają klasy postaci . Jeśli nie określono zakresów, oznacza to niejawnie lub każdy znak w nim razem. Zatem [abcde]jest tym samym, co (a|b|c|d|e), z wyjątkiem tego, że niczego nie rejestruje; będzie on pasował jeden z a, b, c, d, lub e. Cały zakres wskazuje, że jest to zestaw znaków ; [ac-eg]mówi „dopasuj dowolny z a:; dowolny znak między ca e; lub g”. Dlatego dopasowanie mówi „dopasuj dowolny z 0:; dowolny znak pomiędzy 1a 1( tj. Po prostu 1); lub 2.

Twoim celem jest ewidentnie określenie zakresu liczbowego: dowolnej liczby między dwiema cyframi 01i 12zapisywanej za pomocą dwóch cyfr. W tym konkretnym przypadku możesz go dopasować za pomocą 0[1-9]|1[0-2]: a, 0po którym następuje dowolna cyfra między 1i 9, lub a, 1po którym następuje dowolna cyfra między 0a 2. Ogólnie rzecz biorąc, w podobny sposób można przekształcić dowolny zakres liczb w prawidłowe wyrażenie regularne. Jednak może istnieć lepsza opcja niż wyrażenia regularne lub istniejąca funkcja lub moduł, który może utworzyć za Ciebie wyrażenie regularne. To zależy od twojego języka.


0

Jak mówi polygenelubricants, twój będzie szukał 0 | 1-1 | 2 zamiast tego, czego chcesz, ze względu na fakt, że klasy znaków (rzeczy w []) pasują do znaków, a nie do łańcuchów.


3
0|1-1|2- ten zapis jest bardzo mylący. Coś takiego 0|1|2byłoby dokładniejsze.
polygenelubricants

0

Użyj tego:

0?[1-9]|1[012]
  • 07: ważne
  • 7: ważne
  • 0: nie pasuje
  • 00: nie pasuje
  • 13: nie pasuje
  • 21: nie pasuje

Aby przetestować wzór jako 07/2018, użyj tego:

/^(0?[1-9]|1[012])\/([2-9][0-9]{3})$/

(Zakres dat od 01/2000 do 12/9999)


Próbowałem wymyślić, jak to zrobić, ale aby trzeci warunek tylko 0 był spełniony.
mkaatman,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.