Risposte:
Sto usando quanto segue con grande successo:
(["'])(?:(?=(\\?))\2.)*?\1
Supporta anche le virgolette nidificate.
Per coloro che desiderano una spiegazione più approfondita di come funziona, ecco una spiegazione da parte dell'utente effimero :
([""'])
abbinare un preventivo;((?=(\\?))\2.)
se esiste una barra rovesciata, divorala e, se ciò accade, abbina un personaggio;*?
abbinare più volte (non avidamente, per non mangiare la citazione di chiusura);\1
corrisponde alla stessa citazione utilizzata per l'apertura.
"foo\"
. Il trucco del futuro rende ?
possessivo il quantificatore (anche se il sapore regex non supporta la ?+
sintassi o il raggruppamento atomico)
(["'])(?:\\.|[^\\])*?\1
In generale, il seguente frammento di espressione regolare è ciò che stai cercando:
"(.*?)"
Questo utilizza il non avido *? operatore per catturare tutto fino a ma senza includere la prossima doppia citazione. Quindi, si utilizza un meccanismo specifico della lingua per estrarre il testo corrispondente.
In Python, puoi fare:
>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']
"hello \" world"
"(.*?(?<!\\))"
Vorrei andare per:
"([^"]*)"
Il [^ "] è regex per qualsiasi personaggio tranne ' " '
Il motivo per cui lo uso su molti operatori non avidi è che devo continuare a cercarlo solo per assicurarmi di averlo corretto.
Vediamo due modi efficaci per gestire le citazioni di escape. Questi modelli non sono progettati per essere concisi né estetici, ma per essere efficienti.
In questi modi viene utilizzata la prima discriminazione di caratteri per trovare rapidamente le virgolette nella stringa senza il costo di un'alternanza. (L'idea è di scartare rapidamente i caratteri che non sono virgolette senza testare i due rami dell'alternanza.)
Il contenuto tra virgolette viene descritto con un ciclo non srotolato (anziché una ripetuta alternanza) per essere anche più efficiente: [^"\\]*(?:\\.[^"\\]*)*
Ovviamente per gestire stringhe che non hanno virgolette bilanciate, puoi usare invece quantificatori possessivi: [^"\\]*+(?:\\.[^"\\]*)*+
o una soluzione alternativa per emularli, per evitare troppi backtracking. Puoi anche scegliere che una parte tra virgolette possa essere una virgoletta di apertura fino alla virgoletta successiva (senza escape) o alla fine della stringa. In questo caso non è necessario utilizzare quantificatori possessivi, è sufficiente rendere facoltativo l'ultimo preventivo.
Avviso: a volte le virgolette non sono sfuggite a una barra rovesciata ma ripetendo la citazione. In questo caso il sottotitolo del contenuto è simile al seguente:[^"]*(?:""[^"]*)*
I modelli evitano l'uso di un gruppo di acquisizione e un backreference (intendo qualcosa di simile (["']).....\1
) e usano una semplice alternanza ma con ["']
all'inizio, in fattore.
Perl piace:
["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
(si noti che (?s:...)
è uno zucchero sintattico per attivare la modalità dotall / singleline all'interno del gruppo non di acquisizione. Se questa sintassi non è supportata, è possibile attivare facilmente questa modalità per tutto il modello o sostituire il punto con [\s\S]
)
(Il modo in cui questo modello è scritto è totalmente "guidato dalla mano" e non tiene conto di eventuali ottimizzazioni interne del motore)
Sceneggiatura ECMA:
(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
POSIX esteso:
"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
o semplicemente:
"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
/pattern/
senza sfuggire a nulla (invece della notazione dell'oggetto new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");
)
s
qui: (?s:
e se metti (?s)
da qualche parte nel modello.
Il RegEx della risposta accettata restituisce i valori comprese le virgolette circostanti: "Foo Bar"
e "Another Value"
come corrispondenze.
Ecco RegEx che restituisce solo i valori tra virgolette (come stava chiedendo l'interrogatore):
Solo virgolette doppie (utilizzare il valore del gruppo di acquisizione n. 1):
"(.*?[^\\])"
Solo virgolette singole (utilizzare il valore del gruppo di acquisizione n. 1):
'(.*?[^\\])'
Entrambi (utilizzare il valore del gruppo di acquisizione n. 2):
(["'])(.*?[^\\])\1
-
Tutte le virgolette di escape e nidificate supportano.
src="(.*)"
ma ovviamente stava selezionando tutto prima dell'ultimo ", tuttavia il tuo REGEX ha selezionato solo i contenuti src =" ", ma non ho capito come?
Stranamente, nessuna di queste risposte produce una regex in cui la corrispondenza restituita è il testo all'interno delle virgolette, che è ciò che viene richiesto. MA-Madden ci prova ma ottiene solo la partita interna come gruppo catturato piuttosto che l'intera partita. Un modo per farlo effettivamente sarebbe:
(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)
Esempi per questo possono essere visti in questa demo https://regex101.com/r/Hbj8aP/1
La chiave qui è lo sguardo positivo all'inizio (il ?<=
) e lo sguardo positivo alla fine (il ?=
). Il lookbehind sta guardando dietro il personaggio attuale per cercare una citazione, se trovato inizia da lì e poi il lookahead sta controllando il personaggio in anticipo per una citazione e se trovato si ferma su quel personaggio. Il gruppo lookbehind (il ["']
) è racchiuso tra parentesi quadre per creare un gruppo per qualsiasi citazione trovata all'inizio, che viene quindi utilizzata alla fine del lookahead (?=\1)
per assicurarsi che si fermi solo quando trova la citazione corrispondente.
L'unica altra complicazione è che, poiché il lookahead non consuma effettivamente la virgoletta finale, verrà ritrovato dal lookbehind iniziale che fa corrispondere il testo tra virgolette finali e iniziali sulla stessa riga. Mettere un limite di parola nella citazione iniziale ( ["']\b
) aiuta in questo, anche se idealmente mi piacerebbe passare oltre il lookahead ma non penso che sia possibile. La parte che permette ai personaggi fuggiti nel mezzo l'ho presa direttamente dalla risposta di Adam.
Lo schema (["'])(?:(?=(\\?))\2.)*?\1
sopra fa il lavoro ma sono preoccupato per le sue prestazioni (non è male ma potrebbe essere migliore). Il mio sotto è ~ 20% più veloce.
Il modello "(.*?)"
è solo incompleto. Il mio consiglio per tutti coloro che leggono questo è NON USARLO !!!
Ad esempio, non è in grado di catturare molte stringhe (se necessario posso fornire un esaustivo test-case) come quello qui sotto:
$ string = 'Come stai? Sto
\'
bene, grazie ';
Gli altri sono "buoni" come quelli sopra.
Se ti interessano davvero sia le prestazioni che la precisione, inizia con quello qui sotto:
/(['"])((\\\1|.)*?)\1/gm
Nei miei test ha riguardato tutte le stringhe che ho incontrato, ma se trovi qualcosa che non funziona lo aggiornerei volentieri per te.
Mi è piaciuta la soluzione di Eugen Mihailescu per abbinare il contenuto tra virgolette pur consentendo di sfuggire alle citazioni. Tuttavia, ho scoperto alcuni problemi con l'escaping e ho trovato la seguente regex per risolverli:
(['"])(?:(?!\1|\\).|\\.)*\1
Fa il trucco ed è ancora piuttosto semplice e facile da mantenere.
Demo (con alcuni altri casi di test; sentiti libero di usarlo ed espanderlo).
PS: se vuoi solo il contenuto tra virgolette nell'intera corrispondenza ( $0
) e non hai paura del penalità prestazionale, usa:
(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)
Sfortunatamente, senza le virgolette come ancore, ho dovuto aggiungere un limite \b
che non gioca bene con spazi e caratteri di confine non parole dopo la citazione iniziale.
In alternativa, modifica la versione iniziale semplicemente aggiungendo un gruppo ed estraendo il modulo stringa$2
:
(['"])((?:(?!\1|\\).|\\.)*)\1
PPS: se il tuo focus è esclusivamente sull'efficienza, scegli la soluzione di Casimir et Hippolyte ; è buono.
-
, come nelle coordinate di longitudine.
Questa versione
controlla il backtracking
/(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
ALTRE RISPOSTE! Ecco la soluzione che ho usato
\"([^\"]*?icon[^\"]*?)\"
TLDR;
sostituisci l' icona della parola con quello che cerchi tra citazioni e voilà!
Il modo in cui funziona è che cerca la parola chiave e non importa cos'altro tra le virgolette. Ad esempio:
id="fb-icon"
id="icon-close"
id="large-icon-close"
il regex cerca un segno di virgolette, "
quindi cerca ogni possibile gruppo di lettere che non "
arriva fino a quando non trova icon
e ogni possibile gruppo di lettere che non "
lo è, quindi cerca una chiusura"
name="value"
con name={"value"}
poiché la regex di questa risposta ritorna icon
/ value
come secondo gruppo (a differenza della risposta accettata). Trova : =\"([^\"]*?[^\"]*?)\"
Sostituisci :={"$1"}
Mi è piaciuta la versione più espansiva di Axeman, ma ho avuto qualche problema con esso (non corrispondeva ad esempio
foo "string \\ string" bar
o
foo "string1" bar "string2"
correttamente, quindi ho provato a risolverlo:
# 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)
prova questo, funziona come un incanto !!!
\
indica il carattere di salto
" foo bar" "loloo"
. Ho il sospetto che si intende per avvolgere che in una stringa cruda come avete fatto con la regex: r'"\" foo bar\" \"loloo\""'
. Si prega di utilizzare le eccellenti capacità di formattazione di SO ogni volta che è appropriato. Non sono solo cosmetici; non possiamo letteralmente dire cosa stai cercando di dire se non li usi. E benvenuti a Stack Overflow !
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'
Ciò comporterà:> Foo Bar <> <> ma questo <
Qui ho mostrato la stringa di risultato tra> <'s per chiarezza, anche usando la versione non avida con questo comando sed prima buttiamo via la spazzatura prima e dopo quella "" e poi la sostituiamo con la parte tra "" e circondalo con> <'s.
Da Greg H. sono stato in grado di creare questa regex per soddisfare le mie esigenze.
Avevo bisogno di abbinare un valore specifico che si qualificava tra virgolette. Deve essere una partita completa, nessuna corrispondenza parziale potrebbe innescare un colpo
ad es. "test" non può corrispondere a "test2".
reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
print "winning..."
Cacciatore
Se stai cercando di trovare stringhe che hanno solo un certo suffisso, come la sintassi del punto, puoi provare questo:
\"([^\"]*?[^\"]*?)\".localized
Dove .localized
il suffisso.
Esempio:
print("this is something I need to return".localized + "so is this".localized + "but this is not")
Catturerà "this is something I need to return".localized
e "so is this".localized
non "but this is not"
.
Una risposta supplementare per il sottoinsieme di programmatori Microsoft VBA utilizza solo una libreria Microsoft VBScript Regular Expressions 5.5
e ciò fornisce il seguente codice
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
Per me ha funzionato questo:
|([\'"])(.*?)\1|i
Ho usato in una frase come questa:
preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);
e ha funzionato alla grande.
Tutte le risposte sopra sono buone .... tranne che NON supportano tutti i caratteri Unicode! presso ECMA Script (Javascript)
Se sei un utente Node, potresti desiderare la versione modificata della risposta accettata che supporti tutti i caratteri Unicode:
/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu
Prova qui .
? The preceding token is not quantifiable