Wyrażenie regularne zatrzymujące się przy pierwszym dopasowaniu

528

Mój wzór wyrażenia regularnego wygląda mniej więcej tak

<xxxx location="file path/level1/level2" xxxx some="xxx">

Interesuje mnie tylko ta część cytatów przypisanych do lokalizacji. Czy nie powinno być tak łatwe jak poniżej bez chciwego przełącznika?

/.*location="(.*)".*/

Nie wydaje się działać.

publicRavi
źródło
Jakie jest twoje źródło, czy to HTML, xml czy coś?
Oskar Kjellin
20
Dlaczego jest to wiki społeczności? To prawdziwe pytanie. Teraz już za późno.
Ahmad Mageed
1
W jakim języku piszesz? Proszę nie używać wyrażenia regularnego dla XML. Jest wiele lepszych sposobów na parsowanie XML
Oskar Kjellin
3
Nie, jeśli wszystko, czego chcesz, to skanowanie w poszukiwaniu prostych atrybutów. Regex jest odpowiedni i szybszy.
codenheim
Powiedziałbym, że jeśli na przykład użyjesz kodu c #, o wiele lepiej jest użyć do tego linq. Wątpię, czy lepiej będzie regex, jeśli masz dobry parser
Oskar Kjellin

Odpowiedzi:

1092

Musisz sprawić, by wyrażenie regularne nie było zachłanne, ponieważ domyślnie "(.*)"będzie pasowało do wszystkich "file path/level1/level2" xxx some="xxx".

Zamiast tego możesz sprawić, by twoja gwiazda kropka nie była chciwa, co sprawi, że będzie pasować jak najmniej znaków:

/location="(.*?)"/

Dodanie ?na kwantyfikatorem ( ?, *lub +) sprawia, że nie chciwi.

Daniel Vandersluis
źródło
32
FWIW, okrywać swoich potrzeb za pomocą vim regex to być trochę inaczej: zamiast .*?to .\{-}dla nie-chciwy meczu.
SooDesuNe
44
Dzięki Daniel. „Dodanie? Do kwantyfikatora (?, * Lub +) powoduje, że nie jest on chciwy.” jest dla mnie pomocna wskazówka.
PhatHV,
10
The? opisuje moje zamieszanie przy próbie zrozumienia tego. Jak odpowiedni.
Robbie Smith,
1
Wierzę, że można powiedzieć „leniwy” zamiast „nie chciwy”
Manticore,
50

location="(.*)"dopasuje od „po location=do” po, some="xxxchyba że sprawisz, że nie będzie chciwy. Więc albo musisz .*?(tj. Sprawić, że będzie niechciany), albo lepiej zastąp .*go [^"]*.

sepp2k
źródło
3
[^ "] * jest również prawdopodobnie szybszy w przypadku większości silników wyrażeń regularnych, ponieważ nie musi wyszukiwać wzorca po bieżącym wzorcu.
Jean Vincent
1
@Kip: Prawdopodobnie masz rację, ale .*?notacja jest bardziej ogólna niż[^"]*
Bondax
co powiesz na to, czy chcę dołączyć znak ogranicznika za pomocą [^ "] *
Frohlich,
wcale nie, jeśli nie wiesz, co oznaczają ^ i []. Większość ludzi zrozumie. *
Vincent Gerris,
31

Co powiesz na

.*location="([^"]*)".*

Pozwala to uniknąć nieograniczonego wyszukiwania za pomocą. * I pasuje dokładnie do pierwszego cytatu.

193690
źródło
Ze względu na rozbieżności w grep, powyższy powinien być preferowanym wzorcem, jeśli chodzi o przenośność.
Josh Habdas,
22

Użyj niepochodnego dopasowania, jeśli Twój silnik to obsługuje. Dodaj ? wewnątrz schwytania.

/location="(.*?)"/
codenheim
źródło
11

Odpowiedzią jest użycie leniwych kwantyfikatorów ?bez flagi globalnej.

Na przykład,

wprowadź opis zdjęcia tutaj

Gdybyś miał /gwtedy flagę globalną , pasowałby do wszystkich dopasowań o najniższej długości, jak poniżej. wprowadź opis zdjęcia tutaj

Uddhav Gautam
źródło
1

Ponieważ używasz ilościowego subpattern i jak opisano w Perl Doc ,

Domyślnie kwantyfikowany wzorzec jest „ zachłanny ”, to znaczy będzie pasował tyle razy, ile to możliwe (biorąc pod uwagę konkretną lokalizację początkową), jednocześnie umożliwiając dopasowanie pozostałej części wzorca. Jeśli chcesz, aby odpowiadała minimalnej możliwej liczbie razy , podążaj za kwantyfikatorem za pomocą „?” . Zauważ, że znaczenia się nie zmieniają, tylko „chciwość”:

*?        //Match 0 or more times, not greedily (minimum matches)
+?        //Match 1 or more times, not greedily

Dlatego, aby pozwolić twojemu wzorcu ilościowemu na dopasowanie minimalne, wykonaj następujące czynności ?:

/location="(.*?)"/
Mohammad Kanan
źródło
1

Oto inny sposób.

Oto ten, którego chcesz. To jest leniwe[\s\S]*?

Pierwszy element: [\s\S]*?(?:location="[^"]*")[\s\S]* Zamień na:$1

Wyjaśnienie : https://regex101.com/r/ZcqcUm/2


Dla kompletności otrzymuje się ostatni. To jest chciwe[\s\S]*

Ostatni element:[\s\S]*(?:location="([^"]*)")[\s\S]* Zamień na:$1

Wyjaśnienie : https://regex101.com/r/LXSPDp/3


Jest tylko jedna różnica między tymi dwoma wyrażeniami regularnymi i to jest ?

Stephen Sherry
źródło