Regex dla łańcucha nie kończącego się danym przyrostkiem


190

Nie udało mi się znaleźć odpowiedniego wyrażenia regularnego pasującego do dowolnego ciągu nie kończącego się jakimś warunkiem. Na przykład nie chcę dopasowywać niczego, co kończy się na a.

To pasuje

b
ab
1

To nie pasuje

a
ba

Wiem, że wyrażenie regularne powinno kończyć się, $aby zaznaczyć koniec, choć nie wiem, co powinno go poprzedzić.

Edycja : oryginalne pytanie nie wydaje się być dobrym przykładem dla mojej sprawy. Więc: jak poradzić sobie z więcej niż jedną postacią? Powiedz, że coś się nie kończy ab?

Udało mi się to naprawić za pomocą tego wątku :

.*(?:(?!ab).).$

Chociaż wadą jest to, że nie pasuje do ciągu jednej postaci.


5
To nie jest duplikat połączonego pytania - dopasowanie tylko do końca wymaga innej składni niż dopasowanie w dowolnym miejscu ciągu. Wystarczy spojrzeć na najwyższą odpowiedź tutaj.
jaustin

Zgadzam się, to nie jest duplikat powiązanego pytania. Zastanawiam się, jak możemy usunąć powyższe „znaki”?
Alan Cabrera,

Nie ma takiego linku, który mogę zobaczyć.
Alan Cabrera,

Odpowiedzi:


252

Nie podajesz nam języka, ale jeśli twoje wsparcie smaku wyrażenia regularnego wygląda za asercją , oto czego potrzebujesz:

.*(?<!a)$

(?<!a) to negowane twierdzenie, które zapewnia, że ​​przed końcem łańcucha (lub wiersza z m modyfikatorem) nie będzie znaku „a”.

Zobacz to tutaj na Regexr

Możesz również z łatwością rozszerzyć to o inne znaki, ponieważ to sprawdzanie łańcucha i nie jest klasą znaków.

.*(?<!ab)$

To pasowałoby do wszystkiego, co nie kończy się na „ab”, zobacz to na Regexr


1
Nie znam RegexPAL, ale wyrażenia regularne są różne we wszystkich językach i spójrz na to, że twierdzenia są zaawansowaną funkcją, która nie jest obsługiwana przez wszystkich.
stema

7
regexpal to tester wyrażeń regularnych oparty na javascript, a javascript nie obsługuje twierdzeń lookbehind, co jest smutne
HamZa

Lookbehinds nie są obsługiwane w regexr (javascript)
Stealth Rabbi

1
Brak spojrzeń w JS sprawia, że ​​płaczę. Jeśli pracujesz po stronie serwera, prawdopodobnie możesz użyć modułu PCRE na NPM lub podobnego, aby użyć ich bezpośrednio (jest to zestaw powiązań, więc nie sądzę, że możesz go użyć jako front-end)
Eirik Birkeland

Więcej rodzajów asercji lookahead / lookbehind: stackoverflow.com/q/2973436/12484
Jon Schneider

76

Użyj symbolu not ( ^):

.*[^a]$

Jeśli umieścisz ^symbol na początku nawiasów, oznacza to „wszystko oprócz rzeczy w nawiasach”. $jest po prostu kotwicą do końca.

W przypadku wielu znaków po prostu umieść je wszystkie we własnym zestawie znaków:

.*[^a][^b]$

1
+1, z zastrzeżeniem, że nie pasuje do pustego ciągu (który może, ale nie musi być zgodny z przeznaczeniem), więc znaczenie to raczej „dowolny znak, który nie jest w nawiasach”.
Fred Foo

3
@ 0A0D: ciąg zawierający białe znaki nie jest ciągiem pustym.
Fred Foo

7
@ 0A0D Właściwie to nie jest przedmiotem dyskusji, to fakt
tckmn

8
@Doorknob: to nie pasuje aelub cb.
Fred Foo

1
Nie, to też nie pozwoli na „acb”.
Menno

49

Aby wyszukać pliki nie kończące się na „.tmp”, używamy następującego wyrażenia regularnego:

^(?!.*[.]tmp$).*$

Testowany za pomocą Regex Testera daje następujący wynik:

wprowadź opis zdjęcia tutaj


1
To interesujące, każdy pomysł, dlaczego to działa, a dlaczego ^.*(?![.]tmp$)nie?
Łukasz Zaroda,

4
Twoje wczesne .*dopasowanie już pasuje do całego ciągu, więc pozostałe wykluczenie już nie działa.
FiveO

Dla moich celów to zadziałało, a inne odpowiedzi nie. Dzięki!
David Moritz,

8
.*[^a]$

Wyrażenie regularne powyżej dopasuje ciągi, które nie kończą się na a.


Rozszerzyłem moje pytanie, ponieważ oryginalny przykład nie do końca pasował do mojej sprawy. Czy potrafisz to rozwiązać?
Menno

5

Spróbuj tego

/.*[^a]$/

[]Oznacza klasę postaci, a ^odwraca klasa znaków dopasować wszystko, ale a.


1

Pytanie jest stare, ale nie mogłem znaleźć lepszego rozwiązania, które zamieściłbym tutaj. Znajdź wszystkie dyski USB, ale nie wyświetlaj listy partycji , usuwając w ten sposób „część [0–9]” z wyników. Skończyłem robić dwa grep, ostatni neguje wynik:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -vE "part[0-9]*$"

To wyniki w moim systemie:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Jeśli chcę tylko partycje, mógłbym to zrobić:

ls -1 /dev/disk/by-path/* | grep -P "\-usb\-" | grep -E "part[0-9]*$"

Gdzie dostanę:

pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part1
pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0-part2

A kiedy to zrobię:

readlink -f /dev/disk/by-path/pci-0000:00:0b.0-usb-0:1:1.0-scsi-0:0:0:0

Dostaję:

/dev/sdb

1

Zaakceptowana odpowiedź jest w porządku, jeśli możesz użyć lookarounds. Istnieje jednak inne podejście do rozwiązania tego problemu.

Jeśli spojrzymy na szeroko proponowany regex dla tego pytania:

.*[^a]$

Przekonamy się, że to prawie działa. Nie przyjmuje pustego ciągu, co może być trochę niewygodne. Jest to jednak drobny problem w przypadku tylko jednej postaci. Jeśli jednak chcemy wykluczyć cały ciąg, np. „Abc”, to:

.*[^a][^b][^c]$

nie zrobię. Na przykład nie akceptuje ac.

Istnieje jednak proste rozwiązanie tego problemu. Możemy po prostu powiedzieć:

.{,2}$|.*[^a][^b][^c]$

lub bardziej ogólna wersja:

.{,n-1}$|.*[^firstchar][^secondchar]$ gdzie n oznacza długość łańcucha chcesz zabronić (za abcto 3), firstchar, secondchar, ... są pierwszym, drugim ... nth znaków Twojego ciąg (dla abcbyłoby a, następnie b, potemc ).

Wynika to z prostej obserwacji, że łańcuch krótszy niż tekst, którego nie zabronimy, nie może zawierać tego tekstu z definicji. Możemy więc zaakceptować wszystko, co jest krótsze („ab” nie jest „abc”), lub wszystko, co wystarcza na tyle długo, abyśmy zaakceptowali, ale bez końca.

Oto przykład find, który usunie wszystkie pliki, które nie są .jpg:

find . -regex '.{,3}$|.*[^.][^j][^p][^g]$' -delete


.{,2}$|.*[^a][^b][^c]$nie pasujeccc
psalety

0

Wszystko, co pasuje do czegoś, co kończy się na --- .*a$Więc jeśli dopasujesz wyrażenie regularne, zaneguj warunek lub alternatywnie możesz również zrobić .*[^a]$gdzie [^a]oznacza wszystko, co jestnot a


0

Jeśli używasz greplub sedskładnia będzie nieco inna. Zauważ, że [^a][^b]metoda sekwencyjna tutaj nie działa:

balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n'
jd8a
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a]$"
8$fb
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^b]$"
jd8a
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a][^c]$"
jd8a
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^b]$"
q(c
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^a^c]$"
8$fb
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c]$"
jd8a
balter@spectre3:~$ printf 'jd8a\n8$fb\nq(c\n' | grep ".*[^b^c^a]$"

FWIW, znajduję te same wyniki w Regex101 , co moim zdaniem jest składnią JavaScript.

Źle: https://regex101.com/r/MJGAmX/2
Dobrze: https://regex101.com/r/LzrIBu/2

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.