Mam taką wartość:
"Foo Bar" "Another Value" something else
Jakie wyrażenie regularne zwróci wartości ujęte w cudzysłów (np. Foo Bar
I Another Value
)?
Mam taką wartość:
"Foo Bar" "Another Value" something else
Jakie wyrażenie regularne zwróci wartości ujęte w cudzysłów (np. Foo Bar
I Another Value
)?
Odpowiedzi:
Z dużym powodzeniem korzystam z następujących:
(["'])(?:(?=(\\?))\2.)*?\1
Obsługuje również zagnieżdżone cytaty.
Dla tych, którzy chcą głębsze wyjaśnienie jak to działa, oto wyjaśnienie od użytkownika ephemient :
([""'])
dopasuj cytat;((?=(\\?))\2.)
jeśli istnieje ukośnik odwrotny, pożreć go i czy tak się stanie, dopasuj znak;*?
dopasuj wiele razy (niechciwie, aby nie zjeść końcowego cytatu);\1
dopasuj ten sam cytat, który został użyty do otwarcia.
"foo\"
. Spojrzenie w przyszłość trik sprawia ?
zaborczy kwantyfikatora (nawet jeśli aromat regex nie obsługuje ?+
grupowanie składni lub atomowej)
(["'])(?:\\.|[^\\])*?\1
Zasadniczo szukasz następującego fragmentu wyrażenia regularnego:
"(.*?)"
To używa non-chciwego *? operator, aby uchwycić wszystko do następnego podwójnego cytatu, ale bez niego. Następnie używasz mechanizmu specyficznego dla języka, aby wyodrębnić dopasowany tekst.
W Pythonie możesz wykonać:
>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']
"hello \" world"
"(.*?(?<!\\))"
Wybrałbym:
"([^"]*)"
[^ „] Jest regex dla każdego znaku z wyjątkiem ' ” '
The powodu Używam tego przez operatora spoza chciwy wielu jest to, że muszę zachować się, że się po prostu upewnić, mogę to poprawić.
Zobaczmy dwa skuteczne sposoby radzenia sobie z cytowanymi cytatami. Wzory te nie mają być zwięzłe ani estetyczne, ale by były skuteczne.
Te sposoby wykorzystują dyskryminację pierwszego znaku, aby szybko znaleźć cudzysłowy w ciągu bez kosztów zmiany. (Chodzi o to, aby szybko odrzucić postacie, które nie są cudzysłowami, bez przetestowania dwóch gałęzi przemian.)
Treść między cytatami jest opisana za pomocą rozwiniętej pętli (zamiast powtarzanej naprzemiennej), aby również była bardziej wydajna: [^"\\]*(?:\\.[^"\\]*)*
Oczywiście, aby poradzić sobie z ciągami, które nie równoważą cytatów, możesz zamiast tego użyć kwantyfikatorów dzierżawczych: [^"\\]*+(?:\\.[^"\\]*)*+
lub obejścia, aby je naśladować, aby zapobiec zbyt dużemu cofaniu się. Możesz również wybrać, że cytowana część może być cytatem otwierającym do następnego (bez zmiany znaczenia) cytatu lub końca łańcucha. W tym przypadku nie ma potrzeby używania kwantyfikatorów dzierżawczych, wystarczy, że ostatni cytat będzie opcjonalny.
Uwaga: czasami cytaty nie są poprzedzane odwrotnym ukośnikiem, ale przez powtórzenie cytatu. W tym przypadku subpattern treści wygląda następująco:[^"]*(?:""[^"]*)*
Wzorce unikają użycia grupy przechwytywania i odnośników wstecznych (mam na myśli coś podobnego (["']).....\1
) i stosują prostą alternatywę, ale z ["']
początkiem.
Perl lubi:
["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
(zwróć uwagę, że (?s:...)
jest to cukier syntaktyczny do włączania trybu dotall / singleline w grupie nie przechwytującej. Jeśli ta składnia nie jest obsługiwana, możesz łatwo włączyć ten tryb dla całego wzorca lub zastąpić kropkę [\s\S]
)
(Sposób, w jaki zapisany jest ten wzorzec, jest całkowicie „obsługiwany ręcznie” i nie uwzględnia ewentualnych wewnętrznych optymalizacji silnika)
Skrypt ECMA:
(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
Rozszerzony POSIX:
"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
lub po prostu:
"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
/pattern/
nie unikając niczego (zamiast notacji obiektowej new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");
)
s
tutaj: (?s:
i umieścisz (?s)
gdzieś we wzorcu.
RegEx zaakceptowanej odpowiedzi zwraca wartości, w tym ich cudzysłowy: "Foo Bar"
i "Another Value"
jako dopasowania.
Oto RegEx, które zwracają tylko wartości między znakami cudzysłowu (jak pytał pytający):
Tylko podwójne cudzysłowy (użyj wartości grupy przechwytywania nr 1):
"(.*?[^\\])"
Tylko pojedyncze cudzysłowy (użyj wartości grupy przechwytywania nr 1):
'(.*?[^\\])'
Oba (użyj wartości grupy przechwytywania nr 2):
(["'])(.*?[^\\])\1
-
Cała obsługa uciekała i zagnieżdżała cytaty.
src="(.*)"
, ale oczywiście to był wybierając wszystko przed ostatnim”Twój REGEX jednak wybrano tylko src =«»zawartość, ale nie rozumiem w jaki sposób?
W szczególności żadna z tych odpowiedzi nie powoduje wyrażenia regularnego, w którym zwróconym dopasowaniem jest tekst w cudzysłowie, o co jest proszony. MA-Madden próbuje, ale zdobywa walkę wewnętrzną jako złapana grupa, a nie cały mecz. Jednym ze sposobów na zrobienie tego byłoby:
(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)
Przykłady tego można zobaczyć w tym demo https://regex101.com/r/Hbj8aP/1
Kluczem jest tutaj pozytywny wygląd na początku ( ?<=
) i pozytywny widok na końcu ( ?=
). Lookbehind spogląda za obecną postacią, aby sprawdzić cytat, jeśli zostanie znaleziony, zacznij od niego, a następnie lookahead sprawdza postać przed cytatem, a jeśli zostanie znaleziony, zatrzymaj się na tej postaci. Grupa lookbehind ( ["']
) jest owinięta w nawiasy kwadratowe, aby utworzyć grupę dla dowolnego cytatu znalezionego na początku, a następnie jest używana na końcu lookahead, (?=\1)
aby upewnić się, że zatrzyma się tylko, gdy znajdzie odpowiedni cytat.
Jedyną inną komplikacją jest to, że ponieważ lookahead tak naprawdę nie zużywa cytatu końcowego, zostanie znaleziony ponownie przez początkowy lookbehind, co powoduje dopasowanie tekstu między końcowymi i początkowymi cytatami w tym samym wierszu. ["']\b
Pomaga to nałożenie granicy słów na cytat otwierający ( ), choć idealnie chciałbym przejść obok perspektywy, ale nie sądzę, aby było to możliwe. Trochę pozwalając na ucieczkę bohaterom w środku wziąłem bezpośrednio z odpowiedzi Adama.
Powyższy wzór (["'])(?:(?=(\\?))\2.)*?\1
spełnia swoje zadanie, ale martwię się o jego występy (nie jest źle, ale mogłoby być lepiej). Moje poniżej jest ~ 20% szybsze.
Wzór "(.*?)"
jest po prostu niepełny. Moja rada dla wszystkich, którzy to czytają, to NIE WYKORZYSTAJ GO !!!
Na przykład nie może przechwycić wielu ciągów (w razie potrzeby mogę dostarczyć wyczerpujący przypadek testowy), taki jak ten poniżej:
$ string = 'Jak się masz? Nic
\'
mi nie jest, dziękuję ”;
Reszta jest tak samo „dobra” jak ta powyżej.
Jeśli naprawdę zależy Ci na wydajności i precyzji, zacznij od tego poniżej:
/(['"])((\\\1|.)*?)\1/gm
W moich testach obejmował każdy napotkany ciąg, ale jeśli znajdziesz coś, co nie działa, chętnie bym go zaktualizował.
Sprawdź mój wzór w internetowym testerze wyrażeń regularnych .
Podobało mi się rozwiązanie Eugena Mihailescu polegające na dopasowywaniu treści między cytatami przy jednoczesnym unikaniu cytatów. Jednak odkryłem pewne problemy z ucieczką i wymyśliłem następujący regex, aby je naprawić:
(['"])(?:(?!\1|\\).|\\.)*\1
To załatwia sprawę i jest nadal dość prosty i łatwy w utrzymaniu.
Demo (z kilkoma więcej przypadków testowych; możesz go używać i rozszerzać).
PS: Jeśli chcesz tylko treść między cytatami w pełnym dopasowaniu ( $0
) i nie boisz się kary za wyniki:
(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)
Niestety, bez cytatów jako kotwic, musiałem dodać granicę, \b
która nie gra dobrze ze spacjami i znakami granicznymi niebędącymi słowami po cytacie początkowym.
Ewentualnie zmodyfikuj wersję początkową, po prostu dodając grupę i wyodrębnij ciąg znaków$2
:
(['"])((?:(?!\1|\\).|\\.)*)\1
PPS: Jeśli koncentrujesz się wyłącznie na wydajności, skorzystaj z rozwiązania Casimira et Hippolyte ; ten jest dobry.
-
, jak we współrzędnych długości geograficznej.
Ta wersja
kontroluje cofanie
/(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
WIĘCEJ ODPOWIEDZI! Oto rozwiązanie, którego użyłem
\"([^\"]*?icon[^\"]*?)\"
TLDR;
zamień ikonę słowa na to, czego szukasz w wymienionych cytatach i voila!
Działa to tak, że szuka słowa kluczowego i nie obchodzi go, co jeszcze pomiędzy cudzysłowami. EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
regex szuka znaku cudzysłowu, "
a następnie szuka dowolnej możliwej grupy liter, która nie jest, "
dopóki nie znajdzie, icon
i każdej możliwej grupy liter, która nie "
jest, wtedy szuka zamknięcia"
name="value"
z name={"value"}
ponieważ regex zwrotów ta odpowiedź w icon
/ value
w drugiej grupie (w przeciwieństwie do akceptowanej odpowiedzi). Znajdź : =\"([^\"]*?[^\"]*?)\"
Zamień :={"$1"}
Podobała mi się bardziej ekspansywna wersja Axemana, ale miałem z nią pewne problemy (na przykład nie pasowała
foo "string \\ string" bar
lub
foo "string1" bar "string2"
poprawnie, więc próbowałem to naprawić:
# opening quote
(["'])
(
# repeat (non-greedy, so we don't span multiple strings)
(?:
# anything, except not the opening quote, and not
# a backslash, which are handled separately.
(?!\1)[^\\]
|
# consume any double backslash (unnecessary?)
(?:\\\\)*
|
# Allow backslash to escape characters
\\.
)*?
)
# same character as opening quote
\1
string = "\" foo bar\" \"loloo\""
print re.findall(r'"(.*?)"',string)
po prostu wypróbuj to, działa jak urok !!!
\
oznacza pominięcie znaku
" foo bar" "loloo"
. Podejrzewam, że chodziło owinąć że w surowym sznurkiem jak zrobiłeś z regex: r'"\" foo bar\" \"loloo\""'
. Proszę korzystać z doskonałych możliwości formatowania SO, gdy jest to właściwe. To nie tylko kosmetyki; dosłownie nie możemy powiedzieć, co próbujesz powiedzieć, jeśli ich nie używasz. Witamy w Stack Overflow !
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'
Spowoduje to:> Foo Bar <> <> ale to <
Tutaj pokazałem łańcuch wyników między> <dla jasności, również używając wersji innej niż chciwa z tym poleceniem sed, najpierw wyrzucamy śmieci przed i po "", a następnie zamieniamy na część między "" i otaczaj to przez> <'s.
Od Grega H. Byłem w stanie stworzyć ten regex zgodnie z moimi potrzebami.
Musiałem dopasować określoną wartość, która została zakwalifikowana przez umieszczenie w cudzysłowie. Musi to być pełny mecz, żadne częściowe dopasowanie nie powinno spowodować trafienia
np. „test” nie może pasować do „test2”.
reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
print "winning..."
myśliwy
Jeśli próbujesz znaleźć ciągi, które mają tylko określony sufiks, na przykład składnię kropkową, możesz spróbować:
\"([^\"]*?[^\"]*?)\".localized
Gdzie .localized
jest przyrostek.
Przykład:
print("this is something I need to return".localized + "so is this".localized + "but this is not")
Będzie przechwytywał "this is something I need to return".localized
i "so is this".localized
nie "but this is not"
.
Dodatkowa odpowiedź dla podzbioru koderów Microsoft VBA tylko jeden korzysta z biblioteki, Microsoft VBScript Regular Expressions 5.5
co daje następujący kod
Sub TestRegularExpression()
Dim oRE As VBScript_RegExp_55.RegExp '* Tools->References: Microsoft VBScript Regular Expressions 5.5
Set oRE = New VBScript_RegExp_55.RegExp
oRE.Pattern = """([^""]*)"""
oRE.Global = True
Dim sTest As String
sTest = """Foo Bar"" ""Another Value"" something else"
Debug.Assert oRE.test(sTest)
Dim oMatchCol As VBScript_RegExp_55.MatchCollection
Set oMatchCol = oRE.Execute(sTest)
Debug.Assert oMatchCol.Count = 2
Dim oMatch As Match
For Each oMatch In oMatchCol
Debug.Print oMatch.SubMatches(0)
Next oMatch
End Sub
Dla mnie pracował ten:
|([\'"])(.*?)\1|i
Użyłem zdania takiego jak ten:
preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);
i działało świetnie.
Wszystkie powyższe odpowiedzi są dobre .... poza tym, że NIE obsługują wszystkich znaków Unicode! w ECMA Script (Javascript)
Jeśli jesteś użytkownikiem Węzła, możesz chcieć zmodyfikowanej wersji zaakceptowanej odpowiedzi, która obsługuje wszystkie znaki Unicode:
/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu
Spróbuj tutaj .
? The preceding token is not quantifiable