Jak znaleźć „To” w ciągu zawierającym tylko „Jest”? Naprawiłbym to za Ciebie, ale nie wiem, które konwencje pojedynczych cudzysłowów / zmiany znaczenia mają zastosowanie w języku, którego używasz.
Właściwie, patrząc na daty, widzę, że drugie pytanie jest duplikatem tego. Tak czy inaczej, koniecznie sprawdź moją odpowiedź .
ridgerunner
@ridgerunner: Głosuję za zamknięciem tego, jak sugerowałeś. To prawda, że inne pytanie jest nowsze, ale jest też znacznie lepsze (głównie dzięki twojej odpowiedzi).
Alan Moore,
Odpowiedzi:
160
/"(?:[^"\\]|\\.)*"/
Działa w The Regex Coach i PCRE Workbench.
Przykład testu w JavaScript:
var s =' function(){ return " Is big \\"problem\\", \\no? "; }';var m = s.match(/"(?:[^"\\]|\\.)*"/);if(m !=null)
alert(m);
Ma sens. Zwykły angielski: dwa cudzysłowy otaczające zero lub więcej „dowolnego znaku, który nie jest cudzysłowem ani ukośnikiem odwrotnym” lub „ukośnikiem odwrotnym, po którym następuje dowolny znak”. Nie mogę uwierzyć, że nie pomyślałem, żeby to zrobić ...
Ajedi, 32
7
Odpowiem sobie. =) (?:...)to grupa pasywna lub nieprzechwytująca. Oznacza to, że nie można później odwołać się do niego.
magras
po wielu poszukiwaniach i testach jest to prawdziwe i jedyne rozwiązanie tego powszechnego problemu. Dzięki!
cancerbero
10
dzięki za to. chciałem również dopasować pojedyncze cytaty, więc ostatecznie dostosowałem to do tego:/(["'])(?:[^\1\\]|\\.)*?\1/
c.nanorc był pierwszym miejscem, do którego pojechałem. Nie mogłem zmusić go do działania jako części dosłownego ciągu C, dopóki podwójnie nie ucieknie wszystkiego takiego" \"(\\\\.|[^\\\"])*\" "
hellork
Działa to z funkcjami egrep i re_comp / re_exec z biblioteki libc.
fk0
19
Jak zapewnia ePharaoh, odpowiedź brzmi
/"([^"\\]*(\\.[^"\\]*)*)"/
Aby powyższe odnosiło się do ciągów w pojedynczych lub podwójnych cudzysłowach, użyj
Jest to jedyny zestaw, który działał dla mnie z pojedynczym, dużym ciągiem cytowanym o rozmiarze 1,5 KB, zawierającym 99 znaków specjalnych. Każde inne wyrażenie na tej stronie zepsuło się w moim edytorze tekstu z powodu przepełnienia. Chociaż większość z nich działa w przeglądarce, tylko o czym należy pamiętać. Fiddle: jsfiddle.net/aow20y0L
Beejor
3
Zobacz odpowiedź @ MarcAndrePoulin poniżej, aby uzyskać wyjaśnienie.
shaunc
10
Większość przedstawionych tutaj rozwiązań wykorzystuje alternatywne ścieżki powtórzeń, np. (A | B) *.
Możesz napotkać przepełnienia stosu na dużych danych wejściowych, ponieważ niektóre kompilatory wzorców implementują to przy użyciu rekurencji.
Zamienianie \"i .przechodzi nad cudzysłowami ze zmianą znaczenia, podczas gdy leniwy kwantyfikator *?zapewnia, że nie przekroczysz końca cytowanego ciągu. Działa z klasami .NET Framework RE
Zaczerpnięte bezpośrednio z man perlresystemu Linux z zainstalowanym Perlem 5.22.0. Jako optymalizacja, to wyrażenie regularne używa „dodatniej” formy obu +i *zapobiega cofaniu się, ponieważ wiadomo z góry, że ciąg bez cudzysłowu zamykającego w żadnym wypadku nie pasowałby .
Ładnie, ale zbyt elastycznie dla żądania (dopasuje pojedyncze cudzysłowy ...). I można to uprościć do /".*?(?<!\)"/, chyba że coś przeoczę. Aha, i niektóre języki (np. JavaScript) niestety nie rozumieją negatywnych wyrażeń typu lookbehind.
PhiLho
1
@PhiLho, samo użycie pojedynczego (? <! \\) zakończy się niepowodzeniem w przypadku odwrotnych ukośników uciekających na końcu ciągu. Jednak prawda o look-backach w JavaScript.
Markus Jarderot
4
Ten działa idealnie na PCRE i nie spada z StackOverflow.
"(.*?[^\\])??((\\\\)+)?+"
Wyjaśnienie:
Każdy cudzysłowie rozpoczyna Char: ";
Może zawierać dowolną liczbę dowolnych znaków: .*?{Lazy match}; kończące się znakiem bez zmiany znaczenia [^\\];
Instrukcja (2) jest opcjonalna Lazy (!), Ponieważ łańcuch może być pusty („”). Więc:(.*?[^\\])??
Wreszcie każdy cytowany ciąg kończy się "znakiem Char ( ), ale można go poprzedzić parzystą liczbą par znaków ucieczki (\\\\)+; i jest Greedy (!) opcjonalne: ((\\\\)+)?+{Greedy matching}, ponieważ łańcuch może być pusty lub bez końcowych par!
jest to bardzo dobre rozwiązanie, ale [^\1]należy je zastąpić, .ponieważ nie ma czegoś takiego jak antyreferencja, a to i tak nie ma znaczenia. pierwszy warunek zawsze będzie pasował, zanim zdarzy się coś złego.
Seph Reed
@SephReed - zastąpienie [^\1]przez .skutecznie zmieniłoby to wyrażenie regularne na, ("|').*?\1a następnie pasowałoby "foo\"do "foo \" bar". To powiedziawszy, [^\1]trudno jest naprawdę pracować. @ Mathiashansen - Lepiej jest, jeśli masz nieporęczny i drogi (?!\1).(więc całe wyrażenie regularne, z pewnymi poprawkami wydajności, byłoby (["'])(?:\\.|(?!\1).)*+\1. +Jest opcjonalne, jeśli twój silnik go nie obsługuje.
Adam Katz
2
Opcja, która nie została wcześniej poruszona, to:
Odwróć sznurek.
Wykonaj dopasowanie na odwróconym łańcuchu.
Ponownie odwróć dopasowane ciągi.
Ma to dodatkową zaletę polegającą na możliwości prawidłowego dopasowania niezamkniętych otwartych tagów.
Powiedzmy, że masz następujący ciąg; String \"this "should" NOT match\" and "this \"should\" match"
Tutaj \"this "should" NOT match\"nie powinno być dopasowane, a "should"powinno być. Ponadto this \"should\" matchpowinny być dopasowane, a \"should\"nie powinny.
Najpierw przykład.
// The input string.const myString ='String \\"this "should" NOT match\\" and "this \\"should\\" match"';// The RegExp.const regExp =newRegExp(// Match close'([\'"])(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))'+'((?:'+// Match escaped close quote'(?:\\1(?=(?:[\\\\]{2})*[\\\\](?![\\\\])))|'+// Match everything thats not the close quote'(?:(?!\\1).)'+'){0,})'+// Match open'(\\1)(?!(?:[\\\\]{2})*[\\\\](?![\\\\]))','g');// Reverse the matched strings.
matches = myString
// Reverse the string..split('').reverse().join('')// '"hctam "\dluohs"\ siht" dna "\hctam TON "dluohs" siht"\ gnirtS'// Match the quoted.match(regExp)// ['"hctam "\dluohs"\ siht"', '"dluohs"']// Reverse the matches.map(x => x.split('').reverse().join(''))// ['"this \"should\" match"', '"should"']// Re order the matches.reverse();// ['"should"', '"this \"should\" match"']
OK, teraz wyjaśnij RegExp. To jest wyrażenie regularne, które można łatwo podzielić na trzy części. Następująco:
# Part 1(['"]) # Match a closing quotation mark " or '(?!# As long as it's not followed by(?:[\\]{2})*# A pair of escape characters[\\]# and a single escape(?![\\])# As long as that's not followed by an escape)# Part 2((?:# Match inside the quotes(?:# Match option 1:
\1 # Match the closing quote(?=# As long as it's followed by(?:\\\\)*# A pair of escape characters
\\ # (?![\\])# As long as that's not followed by an escape)# and a single escape)|# OR(?:# Match option 2:(?!\1).# Any character that isn't the closing quote))*)# Match the group 0 or more times# Part 3(\1)# Match an open quotation mark that is the same as the closing one(?!# As long as it's not followed by(?:[\\]{2})*# A pair of escape characters[\\]# and a single escape(?![\\])# As long as that's not followed by an escape)
Jest to prawdopodobnie dużo jaśniejsze w formie obrazu: wygenerowane za pomocą Regulexa firmy Jex
Należy pamiętać, że wyrażenia regularne nie są srebrną kulą dla wszystkiego, co ciągłe. Niektóre rzeczy są prostsze przy użyciu kursora i liniowego, ręcznego wyszukiwania. CFL by rade dość trywialnie, ale nie ma wielu implementacje CFL (AFAIK).
Podobny problem napotkałem, próbując usunąć cytowane w cudzysłowie ciągi znaków, które mogą przeszkadzać w analizowaniu niektórych plików.
Skończyło się na dwuetapowym rozwiązaniu, które pokonuje wszelkie zawiłe wyrażenia regularne, jakie możesz wymyślić:
line = line.replace("\\\"","\'");// Replace escaped quotes with something easier to handle
line = line.replaceAll("\"([^\"]*)\"","\"x\"");// Simple is beautiful
Łatwiejsze do odczytania i prawdopodobnie bardziej wydajne.
Jeśli Twoim IDE jest IntelliJ Idea, możesz zapomnieć o wszystkich tych bólach głowy i zapisać swoje wyrażenie regularne w zmiennej typu String, a podczas kopiowania i wklejania go w podwójnym cudzysłowie automatycznie zmieni się na akceptowalny format wyrażenia regularnego.
przykład w Javie:
String s ="\"en_usa\":[^\\,\\}]+";
teraz możesz użyć tej zmiennej w swoim wyrażeniu regularnym lub gdziekolwiek.
Odpowiedzi:
Działa w The Regex Coach i PCRE Workbench.
Przykład testu w JavaScript:
źródło
(?:...)
to grupa pasywna lub nieprzechwytująca. Oznacza to, że nie można później odwołać się do niego./(["'])(?:[^\1\\]|\\.)*?\1/
var s = ' my \\"new\\" string and \"this should be matched\"';
tego podejścia przyniesie to nieoczekiwane rezultaty.Ten pochodzi z nanorc.sample dostępnej w wielu dystrybucjach Linuksa. Służy do podświetlania składni napisów w stylu C.
źródło
var s = ' my \\"new\\" string and \"this should be matched\"';
tego podejścia przyniesie to nieoczekiwane rezultaty." \"(\\\\.|[^\\\"])*\" "
Jak zapewnia ePharaoh, odpowiedź brzmi
Aby powyższe odnosiło się do ciągów w pojedynczych lub podwójnych cudzysłowach, użyj
źródło
Większość przedstawionych tutaj rozwiązań wykorzystuje alternatywne ścieżki powtórzeń, np. (A | B) *.
Możesz napotkać przepełnienia stosu na dużych danych wejściowych, ponieważ niektóre kompilatory wzorców implementują to przy użyciu rekurencji.
Na przykład Java: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6337993
Coś takiego:
"(?:[^"\\]*(?:\\.)?)*"
lub ten dostarczony przez Guya Bedforda zmniejszy liczbę kroków parsowania, unikając większości przepełnień stosu.źródło
Zamienianie
\"
i.
przechodzi nad cudzysłowami ze zmianą znaczenia, podczas gdy leniwy kwantyfikator*?
zapewnia, że nie przekroczysz końca cytowanego ciągu. Działa z klasami .NET Framework REźródło
"\\"
var s = ' my \\"new\\" string and \"this should be matched\"';
/"(?:(?:\\"|[^"])*)"/g
to powinno naprawićZaczerpnięte bezpośrednio z
man perlre
systemu Linux z zainstalowanym Perlem 5.22.0. Jako optymalizacja, to wyrażenie regularne używa „dodatniej” formy obu+
i*
zapobiega cofaniu się, ponieważ wiadomo z góry, że ciąg bez cudzysłowu zamykającego w żadnym wypadku nie pasowałby .źródło
powinien działać z dowolnym ciągiem w cudzysłowie
źródło
Ten działa idealnie na PCRE i nie spada z StackOverflow.
Wyjaśnienie:
"
;.*?
{Lazy match}; kończące się znakiem bez zmiany znaczenia[^\\]
;(.*?[^\\])??
"
znakiem Char ( ), ale można go poprzedzić parzystą liczbą par znaków ucieczki(\\\\)+
; i jest Greedy (!) opcjonalne:((\\\\)+)?+
{Greedy matching}, ponieważ łańcuch może być pusty lub bez końcowych par!źródło
"(.*?[^\\])?(\\\\)*"
tutaj jest taki, który działa zarówno z ", jak i", a na początku możesz łatwo dodać inne.
używa odwołania wstecznego (\ 1) do dokładnego dopasowania tego, co jest w pierwszej grupie („lub”).
http://www.regular-expressions.info/backref.html
źródło
[^\1]
należy je zastąpić,.
ponieważ nie ma czegoś takiego jak antyreferencja, a to i tak nie ma znaczenia. pierwszy warunek zawsze będzie pasował, zanim zdarzy się coś złego.[^\1]
przez.
skutecznie zmieniłoby to wyrażenie regularne na,("|').*?\1
a następnie pasowałoby"foo\"
do"foo \" bar"
. To powiedziawszy,[^\1]
trudno jest naprawdę pracować. @ Mathiashansen - Lepiej jest, jeśli masz nieporęczny i drogi(?!\1).
(więc całe wyrażenie regularne, z pewnymi poprawkami wydajności, byłoby(["'])(?:\\.|(?!\1).)*+\1
.+
Jest opcjonalne, jeśli twój silnik go nie obsługuje.Opcja, która nie została wcześniej poruszona, to:
Ma to dodatkową zaletę polegającą na możliwości prawidłowego dopasowania niezamkniętych otwartych tagów.
Powiedzmy, że masz następujący ciąg;
String \"this "should" NOT match\" and "this \"should\" match"
Tutaj\"this "should" NOT match\"
nie powinno być dopasowane, a"should"
powinno być. Ponadtothis \"should\" match
powinny być dopasowane, a\"should\"
nie powinny.Najpierw przykład.
OK, teraz wyjaśnij RegExp. To jest wyrażenie regularne, które można łatwo podzielić na trzy części. Następująco:
Jest to prawdopodobnie dużo jaśniejsze w formie obrazu: wygenerowane za pomocą Regulexa firmy Jex
Obraz na github (Wizualizator wyrażeń regularnych JavaScript.) Przepraszam, nie mam wystarczającej reputacji, aby dołączyć obrazy, więc na razie to tylko link.
Oto streszczenie przykładowej funkcji wykorzystującej tę koncepcję, która jest nieco bardziej zaawansowana: https://gist.github.com/scagood/bd99371c072d49a4fee29d193252f5fc#file-matchquotes-js
źródło
Należy pamiętać, że wyrażenia regularne nie są srebrną kulą dla wszystkiego, co ciągłe. Niektóre rzeczy są prostsze przy użyciu kursora i liniowego, ręcznego wyszukiwania. CFL by rade dość trywialnie, ale nie ma wielu implementacje CFL (AFAIK).
źródło
Bardziej rozbudowana wersja https://stackoverflow.com/a/10786066/1794894
Ta wersja zawiera również
“
i zamykanie”
)źródło
Pomieszane w regexpal i skończyło się na tym wyrażeniu regularnym: (Nie pytaj mnie, jak to działa, ledwo rozumiem, nawet jeśli napisałem to lol)
źródło
Jeśli jest szukany od początku, może to zadziała?
źródło
Podobny problem napotkałem, próbując usunąć cytowane w cudzysłowie ciągi znaków, które mogą przeszkadzać w analizowaniu niektórych plików.
Skończyło się na dwuetapowym rozwiązaniu, które pokonuje wszelkie zawiłe wyrażenia regularne, jakie możesz wymyślić:
Łatwiejsze do odczytania i prawdopodobnie bardziej wydajne.
źródło
Jeśli Twoim IDE jest IntelliJ Idea, możesz zapomnieć o wszystkich tych bólach głowy i zapisać swoje wyrażenie regularne w zmiennej typu String, a podczas kopiowania i wklejania go w podwójnym cudzysłowie automatycznie zmieni się na akceptowalny format wyrażenia regularnego.
przykład w Javie:
teraz możesz użyć tej zmiennej w swoim wyrażeniu regularnym lub gdziekolwiek.
źródło