Jak uzyskać podciąg " It's big \"problem "
przy użyciu wyrażenia regularnego?
s = ' function(){ return " It\'s big \"problem "; }';
Jak uzyskać podciąg " It's big \"problem "
przy użyciu wyrażenia regularnego?
s = ' function(){ return " It\'s big \"problem "; }';
Odpowiedzi:
/"(?:[^"\\]|\\.)*"/
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);
(?:...)
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.
\"(\\.|[^\"])*\"
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
/"([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'/
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.
/"(?:[^"\\]++|\\.)*+"/
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 .
/(["\']).*?(?<!\\)(\\\\)*\1/is
powinien działać z dowolnym ciągiem w cudzysłowie
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!"(.*?[^\\])?(\\\\)*"
tutaj jest taki, który działa zarówno z ", jak i", a na początku możesz łatwo dodać inne.
("| ') (?: \\\ 1 | [^ \ 1]) *? \ 1
używa odwołania wstecznego (\ 1) do dokładnego dopasowania tego, co jest w pierwszej grupie („lub”).
[^\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ć. Ponadto this \"should\" match
powinny 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 = new RegExp(
// 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
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
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).
Bardziej rozbudowana wersja https://stackoverflow.com/a/10786066/1794894
/"([^"\\]{50,}(\\.[^"\\]*)*)"|\'[^\'\\]{50,}(\\.[^\'\\]*)*\'|“[^”\\]{50,}(\\.[^“\\]*)*”/
Ta wersja zawiera również
“
i zamykanie ”
)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)
"(([^"\\]?(\\\\)?)|(\\")+)+"
Jeśli jest szukany od początku, może to zadziała?
\"((\\\")|[^\\])*\"
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.