2012-11-12 15 views
19

W wyrażeniu regularnym muszę wiedzieć, jak dopasować jedną lub drugą rzecz lub obie te wartości (w kolejności). Ale przynajmniej jedna z rzeczy musi tam być.W wyrażeniu regularnym pasuje do jednej rzeczy lub do obu.

Na przykład poniższe wyrażenie regularne

/^([0-9]+|\.[0-9]+)$/ 

dopasuje

234 

i

.56 

ale nie

234.56 

Choć poniższe wyrażenie regularne

/^([0-9]+)?(\.[0-9]+)?$/ 

dopasuje wszystkie trzy z powyższych ciągów, ale również dopasować pusty ciąg, który nie chcemy.

Potrzebuję czegoś, co będzie pasowało do wszystkich trzech powyższych strun, ale nie do pustej struny. Czy istnieje prosty sposób na zrobienie tego?

UPDATE:

Zarówno Andrew i Justin poniżej pracy na uproszczonym przykładzie I, pod warunkiem, ale nie (chyba że się mylę) pracować dla rzeczywistego przypadku użycia, że ​​miałem nadzieję rozwiązać, więc powinienem to teraz załączyć. Oto rzeczywisty regexp Używam:

/^\s*-?0*(?:[0-9]+|[0-9]{1,3}(?:,[0-9]{3})+)(?:\.[0-9]*)?(\s*|[A-Za-z_]*)*$/ 

To będzie pasował

45 
45.988 
45,689 
34,569,098,233 
567,900.90 
-9 
-34 banana fries 
0.56 points 

ale nie pasuje

.56 

i muszę to aby to zrobić.

+0

Jaki język/smak regex? –

+0

Używam JavaScript. – rharrington

+0

Twoja edycja komplikuje sytuację, ale nadal możesz to zrobić w prosty sposób, szczególnie jeśli najpierw podzielisz na spacje. Zobacz moją edycję. –

Odpowiedz

17

W pełni ogólny sposób, zważywszy Wyrażenia regularne /^A$/ i /^B$/ jest:

/^(A|B|AB)$/ 

tj

/^([0-9]+|\.[0-9]+|[0-9]+\.[0-9]+)$/ 

Uwaga inni wykorzystali strukturę swojej przykład dokonać uproszczenia. Konkretnie, oni (niejawnie) zinterpretowali to, aby wyciągnąć wspólne czynniki [0-9]* i [0-9]+ po lewej i prawej stronie.

Działanie tego jest:

  • wszystkie elementy koniec naprzemiennej w [0-9]+, tak ciągnąć, że spośród: /^(|\.|[0-9]+\.)[0-9]+$/
  • Teraz mamy możliwość pusty ciąg w naprzemiennie, więc przepisać to przy użyciu ? (tjużywać równoważność (|a|b) = (a|b)?): /^(\.|[0-9]+\.)?[0-9]+$/
  • Ponownie, naprzemiennie ze wspólną końcówką (\. ten czas): /^((|[0-9]+)\.)?[0-9]+$/
  • wzór (|a+) jest taki sam jak a*, więc w końcu: /^([0-9]*\.)?[0-9]+$/
+0

Dzięki. Nawet nie myślałem o ogólnym rozwiązaniu tej brutalnej siły. – rharrington

4

Tak, można dopasować wszystkie z nich z takim wyrazem:

/^[0-9]*\.?[0-9]+$/ 

Uwaga, to również nie pasuje do łańcucha pustego (twój ostatni warunek).

4

Pewnie. Chcesz opcjonalny kwantyfikator, ?.

/^(?=.)([0-9]+)?(\.[0-9]+)?$/ 

Powyższe jest nieco niewygodne wyglądające, ale chciałem pokazać dokładny wzór z niektórych ? s rzucone w. W tej wersji (?=.) pilnuje nie akceptuje pusty ciąg, bo” dokonano obu klauzul opcjonalnych. Prostsza wersja byłaby to:

/^\d*\.?\d+$/ 

ten spełnia wymagania, w tym zapobiegania pusty ciąg.

Należy pamiętać, że można to wyrazić na wiele sposobów. Niektóre są długie, a niektóre są bardzo zwięzłe, ale they become more complex depending on what you're trying to allow/disallow.

Edit:

Jeśli chcesz, aby dopasować to wewnątrz większego łańcucha, polecam podział na badania i wyniki z /^\d*\.?\d+$/. W przeciwnym razie ryzykujesz albo pasujące rzeczy, takie jak aaa.123.456.bbb lub brakujące mecze (uwierz mi, to zrobisz) Brak wsparcia JavaScript dla lookbehind zapewnia, że ​​będzie możliwe złamanie dowolnego schematu, jaki mogę wymyślić).

Jeśli wiesz na pewno, że nie dostaniesz sznurki jak wyżej, można użyć przerwy słowo zamiast ^$ kotew, ale będzie skomplikowane, ponieważ nie ma przerwy słowo pomiędzy . i (spacją).

/(\b\d+|\B\.)?\d*\b/g 

To powinno wystarczyć. Będzie blokować takie elementy, jak aaa123.456bbb, ale pozwoli na 123, 456 lub 123.456. Pozwoli to na aaa.123.456.bbb, ale jak już powiedziałem, będziesz potrzebował dwóch kroków, jeśli chcesz kompleksowo sobie z tym poradzić.

Edit 2: Twój przypadek użycia

Jeśli chcesz zezwolić spacje na początku, negatywnych ocen pozytywnych słów/i na końcu, to są rzeczywiście dość ścisłe zasady. To dobra rzecz. Można tylko dodać je do najprostszego wzoru powyżej:

/^\s*[-+]?\d*\.?\d+[a-z_\s]*$/i 

Umożliwienie tysiące grup komplikuje się znacznie, a ja proponuję spojrzeć na odpowiedź ja związanej. Oto Otrzymany wzór:

/^\s*[-+]?(\d+|\d{1,3}(,\d{3})*)?(\.\d+)?\b(\s[a-z_\s]*)?$/i 

\b zapewnia, że ​​część numeryczny kończy się cyfrą, i następnie za pomocą co najmniej jednej spacji.

+0

Dzięki! Tak, musimy użyć tysięcy, ponieważ jest to trochę w przód iw tył między użytkownikiem a aplikacją, z możliwością ustawienia wartości w polu wejściowym. Aplikacja będzie zawsze wyświetlać liczbę w polu wprowadzania z separatorami tysięcy, więc jeśli użytkownik ponownie ją przesyła, chcemy ją zweryfikować. – rharrington

0

Może pomaga (aby dać Ci ogólne pojęcie):

(?:((?(digits).^|[A-Za-z]+)|(?<digits>\d+))){1,2} 

Ten wzorzec pasuje znaków, cyfr lub cyfr po char aktów, ale nie znaków następujących po cyfrach. Wzór pasuje do aa, aa11 i 11, ale nie do 11aa, aa11aa lub do pustego łańcucha. Nie daj się zaskoczyć przez ". ^", Co oznacza "postać, po której następuje początek linii", ma to na celu niedopuszczenie do jakiegokolwiek dopasowania.

Ostrzegam, że to nie działa ze wszystkimi smakami regex, twoja wersja regex musi obsługiwać (?(named group)true|false).

Powiązane problemy