Regex - jak dopasować wszystko oprócz określonego wzorca
171
Jak napisać wyrażenie regularne, aby dopasować dowolny ciąg, który nie spełnia określonego wzorca? Mam do czynienia z sytuacją, w której muszę dopasować wzór (A i ~ B).
W tym przykładzie dopasowano trzy cyfry inne niż 999.
Ale jeśli nie masz implementacji wyrażenia regularnego z tą funkcją (zobacz Porównanie smaków wyrażeń regularnych ), prawdopodobnie będziesz musiał samodzielnie zbudować wyrażenie regularne z podstawowymi funkcjami.
Zgodne wyrażenie regularne tylko z podstawową składnią wyglądałoby tak:
[0-8]\d\d|\d[0-8]\d|\d\d[0-8]
To również pasuje do dowolnej sekwencji trzech cyfr, która nie jest 999.
Look-ahead nie jest standardową składnią wyrażeń regularnych, jest to rozszerzenie Perla, będzie działać tylko w Perlu, PCRE (RegEx zgodny z Perl) lub innych niestandardowych implementacjach
Juliano
10
Może nie jest to standardowe rozwiązanie, ale czy większość współczesnych języków go nie obsługuje? Który język nie obsługuje obecnie prognozowania?
Nie wspomniał o tym w pytaniu, ale OP faktycznie używa findstrpolecenia DOS . Zapewnia tylko niewielki podzbiór możliwości, które można znaleźć w narzędziu regex; nie ma wśród nich lookahead. (Właśnie sam dodałem tag findstr .)
Alan Moore,
2
hm, tak, znalazłem teraz w jednym z jego komentarzy do postów. Widziałem Regex w tytule. W każdym razie, jeśli ktoś znajdzie ten post podczas wyszukiwania tego samego wyrażenia regularnego, tak jak ja, może komuś mógłby się przydać :) dzięki za komentarze
Aleks
15
Dopasuj do wzorca i użyj języka hosta, aby odwrócić wynik logiczny dopasowania. Będzie to znacznie bardziej czytelne i łatwiejsze w utrzymaniu.
Wtedy po prostu kończę z (~ A lub B) zamiast (A i ~ B). To nie rozwiązuje mojego problemu.
notnotnot
1
Pseudokod: String toTest; if (toTest.matches (A) AND! toTest.matches (B)) {...}
Ben S
Powinienem był być bardziej jasny - utwory nie są w pełni niezależne. Jeśli A pasuje do części ciągu, obchodzi nas, czy ~ B pasuje do reszty (ale niekoniecznie do całości). Było to dla funkcji findstr wiersza poleceń systemu Windows, która, jak stwierdziłem, jest ograniczona do prawdziwych wyrażeń regularnych, więc kwestia dyskusyjna.
notnotnot
8
nie, wskrzeszając to starożytne pytanie, ponieważ miało proste rozwiązanie, o którym nie wspomniano. (Znalazłem swoje pytanie podczas szukania informacji o zleceniu zlecenia regex .)
Mam do czynienia z sytuacją, w której muszę dopasować wzór (A i ~ B).
Podstawowe wyrażenie regularne do tego jest przerażająco proste: B|(A)
Po prostu zignorujesz ogólne dopasowania i przeanalizujesz przechwytywania z Grupy 1, które będą zawierać A.
Przykład (ze wszystkimi zastrzeżeniami dotyczącymi analizowania html w wyrażeniu regularnym): A to cyfry, B to cyfry w <a tag
To brzmi zbyt dobrze, aby mogło być prawdziwe! Niestety, rozwiązanie to nie jest uniwersalny i nie jest on w Emacs, nawet po wymianie \dz [[:digit:]]. Pierwsza wzmianka o tym jest specyficzna dla Perla i PHP: „Istnieje odmiana składni specyficzna dla Perla i PHP, która zapewnia to samo”.
miguelmorin
4
Uzupełnieniem języka regularnego jest również język regularny, ale aby go skonstruować, musisz zbudować DFA dla języka regularnego i wprowadzić każdą poprawną zmianę stanu na błąd. Zobacz to jako przykład. Strona nie mówi, że została przekonwertowana /(ac|bd)/na /(a[^c]?|b[^d]?|[^ab])/. Konwersja z DFA z powrotem na wyrażenie regularne nie jest trywialna. Łatwiej będzie, jeśli możesz użyć niezmienionego wyrażenia regularnego i zmienić semantykę w kodzie, tak jak sugerowano wcześniej.
Gdybym miał do czynienia z rzeczywistymi wyrażeniami regularnymi, to wszystko byłoby dyskusyjne. Wydaje się, że regex odnosi się teraz do mglistej przestrzeni CSG (?) Dopasowania wzorców, którą obsługuje większość języków. Ponieważ muszę dopasować (A i ~ B), nie ma sposobu, aby usunąć negację i nadal robić to wszystko w jednym kroku.
notnotnot
Lookahead, jak opisano powyżej, zrobiłby to, gdyby findstr zrobił coś poza prawdziwymi wyrażeniami regularnymi DFA. Całość jest trochę dziwna i nie wiem, dlaczego muszę robić to w stylu wiersza poleceń (teraz wsadowo). To tylko kolejny przykład związania moich rąk.
notnotnot
1
@notnot: Używasz findstr w systemie Windows? Wtedy potrzebujesz tylko / v. Na przykład: findstr Plik wejściowy | findstr / v B> outputfile.txt Pierwsza dopasowuje wszystkie linie z A, druga dopasowuje wszystkie linie, które nie mają B.
Juliano
Dzięki! Właśnie tego potrzebowałem. Jednak nie zadałem tego pytania w ten sposób, więc nadal udzielam odpowiedzi Gumbo, aby uzyskać bardziej ogólną odpowiedź.
Prawdopodobnie chcesz wspomnieć, że musisz ponownie dołączyć.
tomdemuyt
Stosuje się podobne podejście replacestr.replace(/re/g, ''), ale nie ma potrzeby ich ponownego łączenia. także jeśli dodasz ładne zakończenie \ s? tak jak str.replace(/\re\s?/g, '')wtedy,
pozbywasz
0
Moja odpowiedź może również rozwiązać Twój problem:
Grupa $2została tam pozbawiona przechwytywania, czego można by uniknąć.
Przykład:
Regex.Match("50% of 50% is 25%", "(\d+\%)|(.+?)");
Pierwsza grupa przechwytywania określa wzorzec, którego chcesz uniknąć. Ostatnia grupa przechwytująca obejmuje wszystko inne. Wystarczy odczytać tę grupę $2.
findstr
tag, ponieważ wszystkie odpowiedzi tutaj nie są prawidłowe dla tagu.Odpowiedzi:
Możesz użyć asercji z wyprzedzeniem:
W tym przykładzie dopasowano trzy cyfry inne niż
999
.Ale jeśli nie masz implementacji wyrażenia regularnego z tą funkcją (zobacz Porównanie smaków wyrażeń regularnych ), prawdopodobnie będziesz musiał samodzielnie zbudować wyrażenie regularne z podstawowymi funkcjami.
Zgodne wyrażenie regularne tylko z podstawową składnią wyglądałoby tak:
To również pasuje do dowolnej sekwencji trzech cyfr, która nie jest
999
.źródło
Jeśli chcesz dopasować słowo A w ciągu, a nie dopasować słowa B. Na przykład: Jeśli masz tekst:
Jeśli chcesz wyszukać wiersze tekstu, które MAJĄ psa dla zwierzaka i NIE MA kota , możesz użyć tego wyrażenia regularnego:
Znajdzie tylko drugą linię:
źródło
findstr
polecenia DOS . Zapewnia tylko niewielki podzbiór możliwości, które można znaleźć w narzędziu regex; nie ma wśród nich lookahead. (Właśnie sam dodałem tag findstr .)Dopasuj do wzorca i użyj języka hosta, aby odwrócić wynik logiczny dopasowania. Będzie to znacznie bardziej czytelne i łatwiejsze w utrzymaniu.
źródło
nie, wskrzeszając to starożytne pytanie, ponieważ miało proste rozwiązanie, o którym nie wspomniano. (Znalazłem swoje pytanie podczas szukania informacji o zleceniu zlecenia regex .)
Podstawowe wyrażenie regularne do tego jest przerażająco proste:
B|(A)
Po prostu zignorujesz ogólne dopasowania i przeanalizujesz przechwytywania z Grupy 1, które będą zawierać A.
Przykład (ze wszystkimi zastrzeżeniami dotyczącymi analizowania html w wyrażeniu regularnym): A to cyfry, B to cyfry w
<a tag
Wyrażenie regularne:
<a.*?<\/a>|(\d+)
Demo (spójrz na grupę 1 w prawym dolnym panelu)
Odniesienie
Jak dopasować wzorzec poza sytuacjami s1, s2, s3
Jak dopasować wzór, chyba że ...
źródło
\d
z[[:digit:]]
. Pierwsza wzmianka o tym jest specyficzna dla Perla i PHP: „Istnieje odmiana składni specyficzna dla Perla i PHP, która zapewnia to samo”.Uzupełnieniem języka regularnego jest również język regularny, ale aby go skonstruować, musisz zbudować DFA dla języka regularnego i wprowadzić każdą poprawną zmianę stanu na błąd. Zobacz to jako przykład. Strona nie mówi, że została przekonwertowana
/(ac|bd)/
na/(a[^c]?|b[^d]?|[^ab])/
. Konwersja z DFA z powrotem na wyrażenie regularne nie jest trywialna. Łatwiej będzie, jeśli możesz użyć niezmienionego wyrażenia regularnego i zmienić semantykę w kodzie, tak jak sugerowano wcześniej.źródło
wzór - dot
zwróci wszystko oprócz wzorca.
Przetestuj tutaj
źródło
replace
str.replace(/re/g, '')
, ale nie ma potrzeby ich ponownego łączenia. także jeśli dodasz ładne zakończenie \ s? tak jakstr.replace(/\re\s?/g, '')
wtedy,Moja odpowiedź może również rozwiązać Twój problem:
https://stackoverflow.com/a/27967674/543814
$1
, przeczytałbyś grupę$2
.$2
została tam pozbawiona przechwytywania, czego można by uniknąć.Przykład:
Regex.Match("50% of 50% is 25%", "(\d+\%)|(.+?)");
Pierwsza grupa przechwytywania określa wzorzec, którego chcesz uniknąć. Ostatnia grupa przechwytująca obejmuje wszystko inne. Wystarczy odczytać tę grupę
$2
.źródło
następnie użyj tego, co przechwytuje grupa 2 ...
źródło