2014-06-08 16 views
6

Biorąc pod uwagę kilka wyrażeń regularnych, czy możemy napisać wyrażenie regularne, które jest równe ich przecięciu?Czy można wyrównać dopasowanie przecięcia dwóch wyrażeń regularnych?

Na przykład, biorąc pod uwagę dwa wyrażenia regularne c[a-z][a-z] i [a-z][aeiou]t ich przecięcia zawiera cat i cut i ewentualnie więcej. Jak możemy napisać wyrażenie regularne dla ich przecięcia?

Dzięki.

+2

Czy interesują Cię matematyczne wyrażenia regularne lub konkretne praktyczne zastosowania, takie jak PCRE? –

+0

@ n.m .: w obu. Do implementacji, python lub perl. – Tim

Odpowiedz

3

Po pierwsze, uzgodnijmy warunki. Moja składniowej założenie będzie, że

skrzyżowaniu kilku regexes jest regex, który pasuje ciągi że każdy z regexes składowych również dopasować.

Walne Wariant

Aby sprawdzić przecięcia dwóch wzorów, ogólna metoda (pseudo-kod):

if match(regex1) && match(regex2) { champagne for everyone! } 

Opcja Regex

W niektórych przypadkach możesz zrobić to samo z uprzedzeniami, ale w przypadku złożonego wyrażeń regularnych nie ma takiej korzyści, niezależnie od tego, Sprawia, że ​​twoje regex jest bardziej niezrozumiałe dla twoich wrogów. Dlaczego małe korzyści? Ponieważ silnik i tak będzie musiał wielokrotnie analizować cały ciąg znaków.

logiczna AND

Ogólny wzór dla i sprawdzając, czy ciąg dokładnie spełnia regex1 i regex2 byłoby:

^(?=regex1$)(?=regex2$) 

$ w każdym uprzedzona gwarantuje, że każdy łańcuch pasuje do wzorca i nic więcej.

Matching kiedy i

Oczywiście, jeśli nie chcą po prostu sprawdzić wartość logiczną AND ale również zrobić rzeczywiste dopasowanie, po lookaheads, można dodać dot-gwiazda konsumować ciągu:

^(?=regex1$)(?=regex2$).* 

Albo ... Po sprawdzeniu pierwszego warunku, po prostu pasuje do drugiego:

^(?=regex1$)regex2$ 

jest to technika używana na przykład w sprawdzaniu poprawności haseł. Aby uzyskać więcej informacji na ten temat, zobacz Mastering Lookahead and Lookbehind.

sekcja Bonus: Związek regexes

Zamiast pracować na skrzyżowaniu, powiedzmy jesteś zainteresowany w związku z następujących regexes, tj, Wyrażenie regularne, która odpowiada jednej z tych regexes:

  1. połowach
  2. CAT1
  3. cat2
  4. cat3
  5. kategorii 5

Osiąga się to za pomocą operatora naprzemiennie |:

catch|cat1|cat2|cat3|cat5 

Ponadto taki regex często mogą być skompresowane, jak w:

cat(?:ch|[1-35]) 
+0

Czy regex (dowolny smak) może to osiągnąć? Czy potrzebujemy jakiegoś języka programowania? – Tim

+0

Myślę, że pseudo kod jest testowanie, czy ciąg jest w ich przecięciu, a nie faktycznie wszystkie ciągi w ich przecięciu. – Tim

+0

@Tim Chcesz reprezentować wszystkie ciągi? Wtedy nie szukasz regexu i źle zrozumiałem twoje pytanie. Dla mnie: "Jak napisać wyrażenie regularne dla ich przecięcia?" Oznacza, że ​​szukasz wyrażeń regularnych, które pasują tylko wtedy, gdy oba wzorce są prawdziwe. Proszę wyjaśnić, czy nadal nie rozumiem. – zx81

5

logiczne i w regex jest reprezentowany przez

(?=...)(?=...) 

So,

(?=[a-z][aeiou]t)(?=c[a-z][a-z]) 

Regular expression visualization

+0

Napisałeś, że kilka sekund po tym, jak dodałem wcześniejszą część mojej odpowiedzi, musimy się mylić z umysłem. :) – zx81

+0

dzięki. Ale co jeśli chcę dopasować ciągi w przecięciu do ciągu? Przegrane nie zwracają dopasowań. Proszę zobaczyć moje pytanie tutaj http://stackoverflow.com/questions/24154025/how-to-write-a-regex-for-intersection-of-two-regexs-which-can-be-used-fo – Tim

6

Przykłady z wczytaniami są łatwe w użyciu, ale technicznie nie są już zwykłymi językami. Jednak możliwe jest skrzyżowanie dwóch języków regularnych, a to uzupełnienie jest regularne.

Pierwsza uwaga, że ​​Wyrażenia regularne można konwertować do iz NFA; obaj są sposobami wyrażania zwykłych języków.

Po drugie, zgodnie z prawem DeMorgan, w

De Morgan's Law as used in the intersection of two regular languages

Zatem są to kroki, aby obliczyć przecięcie dwóch RegExs:

  • Konwersja zarówno RegExs do NFAs.
  • Obliczyć dopełnienie obu NFA.
  • Oblicz połączenie dwóch uzupełnień.
  • Obliczyć dopełnienie tego związku.
  • Konwertuj wynikowy NFA na RegEx.

Niektóre źródła:

+1

NFA uzupełnienia mogą mieć wymiar wykładniczy. –

0

i wykonywania mamy coś takiego w RegEx

(REGEX) (REGEX)

Biorąc przykład

'Cat'.match(/^([A-Za-z]+)([aeiouAEIOU]+)([A-Za-z]+)$/) 
["Cat", "C", "a", "t"] 
'Ca'.match(/^([A-Za-z]+)([aeiouAEIOU]+)([A-Za-z]+)$/) 
//null 
'Cat123'.match(/^([A-Za-z]+)([aeiouAEIOU]+)([A-Za-z]+)$/) 
//null 

gdzie

([A-Za-z]+) //Match All characters 

i

([aeiouAEIOU]+) //Match all vowels 

połączenia ich obu pasuje

([A-Za-Z] +) ([aeiouAEIOU] +) ([A-Za-Z] +)

np

'Hmmmmmm'.match(/^([A-Za-z]+)([aeiouAEIOU]+)([A-Za-z]+)$/) 
//null 
'Stckvrflw'.match(/^([A-Za-z]+)([aeiouAEIOU]+)([A-Za-z]+)$/) 
null 
'StackOverflow'.match(/^([A-Za-z]+)([aeiouAEIOU]+)([A-Za-z]+)$/) 
["StackOverflow", "StackOverfl", "o", "w"] 
+0

Mam trudności z podążaniem za tobą, Harpreet, czy myślisz, że możesz gdzieś zamieścić demo (może [regex101] (http://regex101.com))? – zx81

+0

@ zx81 Nauczyłem się tego z tego linku http://www.zorched.net/2009/05/08/password-strength-validation-withregularne-expressions/ –

+0

@ zx81 tutaj jest wersja demo http://regex101.com/r/eZ2nG3 –

5

W ujęciu matematycznym przecięcie dwóch języków regularnych jest regularne, więc musi istnieć wyrażenie regularne, które je akceptuje.

Budowanie tego za pośrednictwem odpowiednich NFA jest prawdopodobnie najłatwiejsze. Rozważ dwa NFA, które odpowiadają dwóm wyrażeń regularnych. Nowe stany Q to pary (Q1, Q2) z dwóch NFAs. Jeśli występuje przejście (P1, x, Q1) w pierwszym NFA i (P2, x, Q2) w drugim NFA, wtedy i tylko wtedy następuje przejście ((P1, P2), x, (Q1, Q2)) w nowej NFA. Nowy stan (Q1, Q2) jest początkowy/końcowy, zarówno Q1, jak i Q2 są początkowe/końcowe.

Jeśli używasz NFAs z & epsilon; -moves, to także dla każdego przejścia (P1, & epsilon;, Q1) będzie przejście ((P1, P2), & epsilon;, (Q1, P2)) dla wszystkich stwierdza P2. Podobnie dla & epsilon; -moves w drugim NFA.

Teraz przekonwertuj nowy NFA na wyrażenie regularne z dowolnym znanym algorytmem i to wszystko.

Jeśli chodzi o PCRE, nie są one, ściśle mówiąc, wyrażeniami regularnymi. Nie ma sposobu, aby to zrobić w ogólnym przypadku. Czasami możesz użyć wyprzedzających, takich jak ^(?=regex1$)(?=regex2$), ale jest to dobre tylko dla dopasowania całego ciągu i nie jest dobre dla wyszukiwania lub osadzania w innych wyrażeniach regularnych. Bez zakotwiczenia dwie głowice mogą kończyć się pasującymi ciągami o różnej długości. To nie jest skrzyżowanie.

+0

dzięki. Ale co jeśli chcę dopasować ciągi w przecięciu do ciągu?Przegrane nie zwracają dopasowań, a kotwice '$' i '^' wont 'nie pozwalają na dopasowanie w środku ciągu znaków. Proszę zobaczyć moje pytanie tutaj http://stackoverflow.com/questions/24154025/how-to-write-a-regex- for-the-intersection-of-two-regexs-which-can-be-used- info – Tim

+0

@ Tim, masz rację, nie możesz dorównać w środku sznurka z przodkami. To jest ograniczenie tej metody. –

Powiązane problemy