Regex - jak dopasować wszystko oprócz określonego wzorca


Odpowiedzi:


192

Możesz użyć asercji z wyprzedzeniem:

(?!999)\d{3}

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.


1
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?
Bryan Oakley

1
To prawda. Jednak większość odmian wyrażeń regularnych obsługuje tę funkcję (patrz < regular-expressions.info/refflavors.html> ).
Gumbo

1
myślę, że ostatnie wyrażenie regularne również nie pasowałoby do 009, 019 ... itd.
Sebastian Viereck

1
Standardowy Lex dla C nie używa PCRE :-(
pieman72

30

Jeśli chcesz dopasować słowo A w ciągu, a nie dopasować słowa B. Na przykład: Jeśli masz tekst:

1. I have a two pets - dog and a cat
2. I have a pet - dog

Jeśli chcesz wyszukać wiersze tekstu, które MAJĄ psa dla zwierzaka i NIE MA kota , możesz użyć tego wyrażenia regularnego:

^(?=.*?\bdog\b)((?!cat).)*$

Znajdzie tylko drugą linię:

2. I have a pet - dog

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.


1
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

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 ...


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.


2
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ź.
notnotnot

1

wzór - dot

str.split(/re/g) 

zwróci wszystko oprócz wzorca.

Przetestuj tutaj


Prawdopodobnie chcesz wspomnieć, że musisz ponownie dołączyć.
tomdemuyt

Stosuje się podobne podejście replace str.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:

https://stackoverflow.com/a/27967674/543814

  • Zamiast Zamień użyjesz Dopasuj.
  • Zamiast grupy $1, przeczytałbyś grupę $2.
  • 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.


0
(B)|(A)

następnie użyj tego, co przechwytuje grupa 2 ...


Musi zbić nie B, jego celem nie jest po prostu ignorowanie wszystkich wzorów B.
hexicle,
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.