Jak dopasować „cokolwiek aż do tej sekwencji znaków” w wyrażeniu regularnym?

514

Przyjmować tego wyrażenia regularnego: /^[^abc]/. Spowoduje to dopasowanie dowolnego znaku na początku łańcucha, z wyjątkiem a, b lub c.

Jeśli dodasz *po nim - /^[^abc]*/- wyrażenie regularne będzie dodawać każdy kolejny znak do wyniku, dopóki nie spotka się z a, lub b , lub c .

Na przykład w przypadku ciągu źródłowego "qwerty qwerty whatever abc hello"wyrażenie będzie pasować do"qwerty qwerty wh" .

Ale co, jeśli chcę, aby pasował do niego ciąg "qwerty qwerty whatever "

... Innymi słowy, jak mogę dopasować wszystko do dokładnej sekwencji (ale nie w tym) "abc"?

kalus
źródło
Co masz na myśli match but not including?
Toto
5
Mam na myśli, że chcę dopasować "qwerty qwerty whatever "- nie licząc „abc”. Innymi słowy, nie chcę, aby wynikowe dopasowanie było "qwerty qwerty whatever abc".
callum
2
W javascript możesz po prostu do string.split('abc')[0]. Z pewnością nie jest to oficjalna odpowiedź na ten problem, ale uważam, że jest to prostsze niż regex.
Wylliam Judd

Odpowiedzi:

1020

Nie określiłeś, jakiego smaku wyrażenia regularnego używasz, ale zadziała to w jednym z najbardziej popularnych, które można uznać za „kompletne”.

/.+?(?=abc)/

Jak to działa

Ta .+? część to niechciana wersja .+ (jednego lub więcej czegokolwiek). Kiedy używamy .+, silnik zasadniczo wszystko pasuje. Następnie, jeśli w wyrażeniu regularnym jest coś jeszcze, cofnie się w krokach, próbując dopasować następną część. Jest to zachłanne zachowanie, co oznacza jak najwięcej do zaspokojenia .

Podczas używania .+?zamiast dopasowywać wszystkie naraz i wracać do innych warunków (jeśli występują), silnik będzie dopasowywał kolejne znaki krok po kroku, dopóki kolejna część wyrażenia regularnego nie zostanie dopasowana (ponownie, jeśli w ogóle). To jest niechciane , co oznacza dopasowanie najmniejszej możliwej do zaspokojenia .

/.+X/  ~ "abcXabcXabcX"        /.+/  ~ "abcXabcXabcX"
          ^^^^^^^^^^^^                  ^^^^^^^^^^^^

/.+?X/ ~ "abcXabcXabcX"        /.+?/ ~ "abcXabcXabcX"
          ^^^^                          ^

Następnie mamy stwierdzenie o zerowej szerokości i rozejrzyj się . Ta zgrupowana konstrukcja pasuje do jej zawartości, ale nie jest liczona jako dopasowane znaki ( szerokość zero ). Zwraca tylko, jeśli jest to dopasowanie, czy nie ( twierdzenie ).(?={contents})

Zatem, innymi słowy, wyrażenie regularne /.+?(?=abc)/oznacza:

Dopasuj dowolną liczbę znaków tak mało, jak to możliwe, aż do znalezienia „abc”, bez liczenia „abc”.

sidyll
źródło
12
Prawdopodobnie nie zadziała to z podziałami linii, jeśli mają zostać przechwycone.
einord
3
Jaka jest różnica między .+?i .*?
robbie
4
@ robbie0630 +oznacza 1 lub więcej, gdzie *oznacza 0 lub więcej. Włączenie / wyłączenie ?spowoduje, że będzie on chciwy lub niechciany.
jinglesthula,
2
@ testerjoe2 /.+?(?=abc|xyz)/
JohnWrensby
4
Zauważyłem, że to nie wybiera niczego, jeśli wzorzec, którego szukasz, nie istnieje, zamiast tego możesz użyć ^(?:(?!abc)(?!def).)*łańcucha, aby wykluczyć wzorce, których nie chcesz i nadal pobierze wszystko w razie potrzeby, nawet jeśli wzorzec nie istnieje
Karan Shishoo,
122

Jeśli chcesz uchwycić wszystko do „abc”:

/^(.*?)abc/

Wyjaśnienie:

( )uchwycić wyraz wewnątrz nawiasów dostępu użyciu $1, $2itp

^ dopasuj początek linii

.*dopasuj wszystko, ?niechciwie (dopasuj minimalną wymaganą liczbę znaków) - [1]

[1] Powodem, dla którego jest to potrzebne, jest to, że inaczej, w następującym ciągu:

whatever whatever something abc something abc

domyślnie wyrażenia regularne są zachłanne , co oznacza, że ​​będą pasować jak najwięcej. Dlatego /^.*abc/pasowałoby „cokolwiek cokolwiek abc coś”. Dodanie niepochodnego kwantyfikatora ?powoduje, że regex pasuje tylko „cokolwiek, co”.

Jared Ng
źródło
4
Dzięki, ale twój jeden ma obejmować ABC w meczu. Innymi słowy, wynikiem jest „cokolwiek, co abc”.
callum
1
Czy możesz wyjaśnić, co ostatecznie próbujesz zrobić? Jeśli twoim scenariuszem jest: (A) Chcesz uzyskać wszystko, co prowadzi do „abc” - po prostu użyj nawiasów wokół tego, co chcesz uchwycić. (B) Chcesz dopasować ciąg do „abc” - i tak musisz sprawdzić abc, więc niezależnie od tego musi on być częścią wyrażenia regularnego. Jak jeszcze możesz sprawdzić, czy tam jest?
Jared Ng
sedwydaje się nie obsługiwać chciwego dopasowywania, ani nie obsługuje rozglądania się ( (?=...)). Co jeszcze mogę zrobić? Przykładowe polecenie: echo "ONE: two,three, FOUR FIVE, six,seven" | sed -n -r "s/^ONE: (.+?), .*/\1/p"zwraca two,three, FOUR FIVE, ale spodziewam się two,three...
CodeManX
1
@CoDEmanX Prawdopodobnie powinieneś opublikować to jako własne oddzielne pytanie, a nie komentarz, zwłaszcza, że ​​dotyczy to w szczególności sed. Biorąc to pod uwagę, aby odpowiedzieć na twoje pytanie: możesz spojrzeć na odpowiedzi na to pytanie . Zauważ też, że w twoim przykładzie niepochodny świadomy tłumacz wróciłby po prostu two, a nie two,three.
Jared Ng
3
W ten sposób za każdym REGEXP odpowiedź powinna wyglądać - przykład i wyjaśnienie wszystkich części ...
jave.web
54

Jak zauważyli @Jared Ng i @Issun, klucz do rozwiązania tego rodzaju RegEx, np. „Dopasowywanie wszystkiego do określonego słowa lub podłańcucha” lub „dopasowanie wszystkiego po określonym słowie lub podłańcuchu” nazywa się „patrzeniem” na twierdzenia o zerowej długości . Przeczytaj więcej o nich tutaj.

W twoim konkretnym przypadku można to rozwiązać pozytywnie: .+?(?=abc)

Obraz jest wart tysiąca słów. Zobacz szczegółowe wyjaśnienie na zrzucie ekranu.

Zrzut ekranu Regex101

Devy
źródło
23
.+?(?=abc)wyrażenie regularne z możliwością kopiowania jest warte więcej.
Tom
Co z wykluczeniem wiodących miejsc?
Royi
8

To, czego potrzebujesz, to rozejrzyj się wokół takiego stwierdzenia .+? (?=abc) .

Zobacz: asercje Lookahead i Lookbehind o zerowej długości

Pamiętaj, że [abc]to nie to samo, co abc. W nawiasach nie jest to ciąg znaków - każda postać jest tylko jedną z możliwości. Poza nawiasami staje się ciągiem.

aevanko
źródło
7

Dla wyrażeń regularnych w Javie i wierzę również w większość silników wyrażeń regularnych, jeśli chcesz dołączyć ostatnią część, to zadziała:

.+?(abc)

Na przykład w tym wierszu:

I have this very nice senabctence

zaznacz wszystkie znaki do „abc”, a także włącz abc

przy użyciu naszego wyrażenia regularnego wynikiem będzie: I have this very nice senabc

Sprawdź to: https://regex101.com/r/mX51ru/1

Dadan
źródło
4

Zakończyłem to pytanie dotyczące przepełnienia stosu, szukając pomocy w rozwiązaniu mojego problemu, ale nie znalazłem rozwiązania :(

Musiałem więc improwizować ... po pewnym czasie udało mi się dotrzeć do wyrażenia regularnego, którego potrzebowałem:

wprowadź opis zdjęcia tutaj

Jak widać, potrzebowałem do jednego folderu przed folderem „grp-bps”, bez ostatniej kreski. Wymagany był przynajmniej jeden folder po folderze „grp-bps”.

Edytować

Wersja tekstowa do kopiuj-wklej (zmień „grp-bps” na tekst):

.*\/grp-bps\/[^\/]+
Loaderon
źródło
6
Brak wersji tekstowej? 🙄
kiradotee
2

Będzie to miało sens w przypadku wyrażenia regularnego.

  1. Dokładne słowo można uzyskać z następującego polecenia wyrażenia regularnego:

("(.*?)")/sol

Tutaj możemy uzyskać dokładnie to słowo, które należy do podwójnych cudzysłowów. Na przykład jeśli naszym wyszukiwanym tekstem jest,

To jest przykład słów „podwójnie cytowanych”

wtedy otrzymamy „podwójne cytowanie” z tego zdania.

Ponmurugan Mohanraj
źródło
Witamy w StackOverflow i dziękuję za próbę pomocy. Trudno mi jednak dostrzec, w jaki sposób pomaga to celowi postawionemu w pytaniu. Czy możesz rozwinąć? Czy możesz zastosować to do podanych przykładów? Wydaje się, że skupiasz się na obsłudze ", co wydaje mi się nieistotne dla pytania.
Yunnosch
1
Cześć. Wyjaśniłem, jak wstawiać słowo lub zdania między znakami specjalnymi. Tutaj naszym pytaniem jest również „wszystko do sekwencji znaków specjalnych”. więc spróbowałem z podwójnymi cytatami i wyjaśniłem to tutaj. Dzięki.
Ponmurugan Mohanraj
2

W pythonie:

.+?(?=abc) działa w przypadku pojedynczej linii.

[^]+?(?=abc)nie działa, ponieważ python nie rozpoznaje [^] jako poprawnego wyrażenia regularnego. Aby dopasowanie wieloliniowe działało, musisz użyć opcji re.DOTALL, na przykład:

re.findall('.+?(?=abc)', data, re.DOTALL)
David Mulder
źródło
0

Uważam, że potrzebujesz podwyrażeń. Jeśli dobrze pamiętam, możesz użyć normalnego() nawiasów podwyrażeń.

Ta część pochodzi z podręcznika grep:

 Back References and Subexpressions
       The back-reference \n, where n is a single digit, matches the substring
       previously matched  by  the  nth  parenthesized  subexpression  of  the
       regular expression.

Zrób coś takiego, ^[^(abc)]powinno załatwić sprawę.

Nandhini Anand
źródło
Przepraszam, to nie działa Umieszczenie abc w nawiasach nie wydaje się mieć żadnej różnicy. Nadal są traktowane jako „OR b OR c”.
callum
-1

Te $znaki na końcu łańcucha, więc coś jak to powinno działać: [[^abc]*]$gdzie szukasz czegoś nie kończącego się w każdej iteracji abc, ale musiałby to być na końcu

Również jeśli używasz języka skryptowego z wyrażeniem regularnym (takim jak php lub js), mają one funkcję wyszukiwania, która zatrzymuje się, gdy po raz pierwszy napotka wzorzec (i możesz określić początek od lewej lub początek od prawej lub za pomocą php, możesz wykonać implode, aby wykonać kopię lustrzaną łańcucha).

Jakub
źródło
-6

Spróbuj tego

.+?efg

Zapytanie:

select REGEXP_REPLACE ('abcdefghijklmn','.+?efg', '') FROM dual;

wynik :

hijklmn
Balakrishna Gondesi
źródło