Réponses:
J'utilise les éléments suivants avec beaucoup de succès:
(["'])(?:(?=(\\?))\2.)*?\1
Il prend également en charge les citations imbriquées.
Pour ceux qui veulent une explication plus approfondie de la façon dont cela fonctionne, voici une explication de l' éphémient utilisateur :
([""'])
correspondre à un devis;((?=(\\?))\2.)
si une barre oblique inverse existe, engloutissez-la et, que cela se produise ou non, faites correspondre un caractère;*?
correspondre plusieurs fois (sans avidité, pour ne pas manger la citation de clôture);\1
correspondre à la même citation qui a été utilisée pour l'ouverture.
"foo\"
. L'astuce d'anticipation rend le ?
quantificateur possessif (même si la saveur regex ne prend pas en charge la ?+
syntaxe ou le groupement atomique)
(["'])(?:\\.|[^\\])*?\1
En général, le fragment d'expression régulière suivant correspond à ce que vous recherchez:
"(.*?)"
Cela utilise le non gourmand *? opérateur pour tout capturer jusqu'à mais sans inclure la prochaine citation double. Ensuite, vous utilisez un mécanisme spécifique à la langue pour extraire le texte correspondant.
En Python, vous pouvez faire:
>>> import re
>>> string = '"Foo Bar" "Another Value"'
>>> print re.findall(r'"(.*?)"', string)
['Foo Bar', 'Another Value']
"hello \" world"
"(.*?(?<!\\))"
J'irais pour:
"([^"]*)"
Le [^ "] est regex pour tout caractère sauf ' " '.
La raison pour laquelle j'utilise ceci sur l'opérateur many non gourmand, c'est que je dois continuer à chercher cela juste pour m'assurer que je le reçois correctement.
Voyons deux façons efficaces de gérer les guillemets échappés. Ces motifs ne sont pas conçus pour être concis ni esthétiques, mais pour être efficaces.
Ces méthodes utilisent la première discrimination de caractère pour trouver rapidement des guillemets dans la chaîne sans le coût d'une alternance. (L'idée est de supprimer rapidement les caractères qui ne sont pas des guillemets sans tester les deux branches de l'alternance.)
Le contenu entre guillemets est décrit avec une boucle déroulée (au lieu d'une alternance répétée) pour être plus efficace aussi: [^"\\]*(?:\\.[^"\\]*)*
Évidemment, pour traiter les chaînes qui n'ont pas des guillemets équilibrés, vous pouvez utiliser des quantificateurs possessifs à la place: [^"\\]*+(?:\\.[^"\\]*)*+
ou une solution de contournement pour les émuler, pour éviter trop de retour en arrière. Vous pouvez également choisir qu'une partie entre guillemets puisse être une citation d'ouverture jusqu'à la citation suivante (non échappée) ou la fin de la chaîne. Dans ce cas, il n'est pas nécessaire d'utiliser des quantificateurs possessifs, il vous suffit de rendre la dernière citation facultative.
Remarque: parfois, les guillemets ne sont pas échappés par une barre oblique inverse, mais en répétant la citation. Dans ce cas, le sous-modèle de contenu ressemble à ceci:[^"]*(?:""[^"]*)*
Les motifs évitent l'utilisation d'un groupe de capture et d'une référence arrière (je veux dire quelque chose comme (["']).....\1
) et utilisent une alternance simple mais avec ["']
au début, en facteur.
Perl comme:
["'](?:(?<=")[^"\\]*(?s:\\.[^"\\]*)*"|(?<=')[^'\\]*(?s:\\.[^'\\]*)*')
(notez qu'il (?s:...)
s'agit d'un sucre syntaxique pour activer le mode dotall / singleline dans le groupe non capturant. Si cette syntaxe n'est pas prise en charge, vous pouvez facilement activer ce mode pour tout le modèle ou remplacer le point par [\s\S]
)
(La façon dont ce modèle est écrit est totalement "manuelle" et ne tient pas compte des éventuelles optimisations internes du moteur)
Script ECMA:
(?=["'])(?:"[^"\\]*(?:\\[\s\S][^"\\]*)*"|'[^'\\]*(?:\\[\s\S][^'\\]*)*')
POSIX étendu:
"[^"\\]*(\\(.|\n)[^"\\]*)*"|'[^'\\]*(\\(.|\n)[^'\\]*)*'
ou simplement:
"([^"\\]|\\.|\\\n)*"|'([^'\\]|\\.|\\\n)*'
/pattern/
sans rien échapper (au lieu de la notation objet new RegExp("(?=[\"'])(?:\"[^\"\\\\]*...");
)
s
ici: (?s:
et si vous mettez (?s)
quelque part dans le motif.
Le RegEx de la réponse acceptée renvoie les valeurs, y compris leurs guillemets environnants: "Foo Bar"
et "Another Value"
sous forme de correspondances.
Voici RegEx qui ne renvoie que les valeurs entre guillemets (comme l'interrogateur le demandait):
Citations doubles uniquement (utilisez la valeur du groupe de capture n ° 1):
"(.*?[^\\])"
Citations simples uniquement (utilisez la valeur du groupe de capture n ° 1):
'(.*?[^\\])'
Les deux (utilisez la valeur du groupe de capture n ° 2):
(["'])(.*?[^\\])\1
-
Toutes les citations échappées et imbriquées de support.
src="(.*)"
mais évidemment il sélectionnait tout avant le dernier ", votre REGEX, cependant, ne sélectionnait que le contenu src =" ", mais je ne comprenais pas comment?
Curieusement, aucune de ces réponses ne produit une expression régulière où la correspondance renvoyée est le texte à l'intérieur des guillemets, ce qui est demandé. MA-Madden essaie mais n'obtient que le match intérieur en tant que groupe capturé plutôt que le match entier. Une façon de le faire serait:
(?<=(["']\b))(?:(?=(\\?))\2.)*?(?=\1)
Des exemples de cela peuvent être vus dans cette démo https://regex101.com/r/Hbj8aP/1
La clé ici est le lookbehind positif au début (le ?<=
) et le lookahead positif à la fin (le ?=
). Le lookbehind regarde derrière le caractère actuel pour vérifier une citation, s'il est trouvé, commencez à partir de là, puis le lookahead vérifie le caractère à venir pour une citation et s'il est trouvé, arrêtez-vous sur ce caractère. Le groupe de recherche (le ["']
) est placé entre crochets pour créer un groupe pour la citation trouvée au début, il est ensuite utilisé à la fin de l'anticipation (?=\1)
pour s'assurer qu'il ne s'arrête que lorsqu'il trouve la citation correspondante.
La seule autre complication est que, parce que l'antichambre ne consomme pas réellement le guillemet final, il sera retrouvé par le regard de départ qui entraîne la correspondance du texte entre les guillemets de fin et de début sur la même ligne. Mettre une limite de mot sur la citation d'ouverture ( ["']\b
) aide à cela, bien que j'aimerais idéalement passer devant l'antichambre, mais je ne pense pas que ce soit possible. Le bit permettant aux personnages échappés au milieu que j'ai pris directement de la réponse d'Adam.
Le motif (["'])(?:(?=(\\?))\2.)*?\1
ci-dessus fait l'affaire mais je suis préoccupé par ses performances (c'est pas mal mais ça pourrait être mieux). Le mien en dessous est ~ 20% plus rapide.
Le modèle "(.*?)"
est juste incomplet. Mon conseil pour tous ceux qui lisent ceci est juste de ne pas l'utiliser !!!
Par exemple, il ne peut pas capturer de nombreuses chaînes (si nécessaire, je peux fournir un cas de test exhaustif) comme celui ci-dessous:
$ string = 'Comment ça va? Je vais
\'
bien, merci ';
Les autres sont tout aussi "bons" que celui ci-dessus.
Si vous vous souciez vraiment à la fois des performances et de la précision, commencez par celui ci-dessous:
/(['"])((\\\1|.)*?)\1/gm
Dans mes tests, il a couvert toutes les chaînes que j'ai rencontrées, mais si vous trouvez quelque chose qui ne fonctionne pas, je le mettrais à jour avec plaisir.
J'ai aimé la solution d'Eugen Mihailescu pour faire correspondre le contenu entre les citations tout en permettant d'échapper aux citations. Cependant, j'ai découvert quelques problèmes avec l'échappement et j'ai trouvé l'expression régulière suivante pour les résoudre:
(['"])(?:(?!\1|\\).|\\.)*\1
Il fait l'affaire et est toujours assez simple et facile à entretenir.
Démo (avec quelques cas de test supplémentaires; n'hésitez pas à l'utiliser et à l'étendre).
PS: Si vous voulez simplement le contenu entre guillemets dans le match complet ( $0
), et que vous n'avez pas peur de la pénalité de performance, utilisez:
(?<=(['"])\b)(?:(?!\1|\\).|\\.)*(?=\1)
Malheureusement, sans les guillemets comme ancres, j'ai dû ajouter une frontière \b
qui ne fonctionne pas bien avec des espaces et des caractères de frontière non-mot après la citation de départ.
Vous pouvez également modifier la version initiale en ajoutant simplement un groupe et en extraire la forme de chaîne$2
:
(['"])((?:(?!\1|\\).|\\.)*)\1
PPS: Si vous vous concentrez uniquement sur l'efficacité, optez pour la solution de Casimir et Hippolyte ; c'est un bon.
-
, comme dans les coordonnées de longitude.
Cette version
contrôle le retour en arrière
/(["'])((?:(?!\1)[^\\]|(?:\\\\)*\\[^\\])*)\1/
PLUS DE RÉPONSES! Voici la solution que j'ai utilisée
\"([^\"]*?icon[^\"]*?)\"
TLDR;
remplacez l' icône du mot par ce que vous recherchez dans lesdites citations et le tour est joué!
La façon dont cela fonctionne est qu'il recherche le mot-clé et ne se soucie pas de quoi d'autre entre les guillemets. EG:
id="fb-icon"
id="icon-close"
id="large-icon-close"
le regex cherche un guillemet "
puis il cherche tout groupe de lettres
possible qui ne l'est pas "
jusqu'à ce qu'il trouve icon
et tout groupe de lettres possible qui ne l'est pas "
alors il cherche une fermeture"
name="value"
par name={"value"}
puisque l'expression régulière de cette réponse renvoie icon
/ value
comme deuxième groupe (contrairement à la réponse acceptée). Trouver : =\"([^\"]*?[^\"]*?)\"
Remplacer :={"$1"}
J'ai aimé la version plus expansive d'Axeman, mais j'ai eu quelques problèmes avec elle (elle ne correspondait pas par exemple
foo "string \\ string" bar
ou
foo "string1" bar "string2"
correctement, j'ai donc essayé de le réparer:
# 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)
essayez-le, fonctionne comme un charme !!!
\
indique un caractère de saut
" foo bar" "loloo"
. Je pense que vous vouliez dire pour envelopper que dans une chaîne brute comme vous avez fait avec la regex: r'"\" foo bar\" \"loloo\""'
. Veuillez utiliser les excellentes capacités de formatage de SO chaque fois que cela est approprié. Ce n'est pas seulement des cosmétiques; nous ne pouvons littéralement pas dire ce que vous essayez de dire si vous ne les utilisez pas. Et bienvenue dans Stack Overflow !
Contrairement à la réponse d'Adam, j'en ai une simple mais efficace:
(["'])(?:\\\1|.)*?\1
Et ajoutez simplement des parenthèses si vous souhaitez obtenir du contenu entre guillemets comme ceci:
(["'])((?:\\\1|.)*?)\1
Correspond ensuite au caractère de $1
citation et à $2
la chaîne de contenu.
echo 'junk "Foo Bar" not empty one "" this "but this" and this neither' | sed 's/[^\"]*\"\([^\"]*\)\"[^\"]*/>\1</g'
Cela se traduira par:> Foo Bar <> <> mais ce <
Ici, j'ai montré la chaîne de résultat entre> <pour plus de clarté, en utilisant également la version non gourmande avec cette commande sed, nous jetons d'abord les fichiers indésirables avant et après ces "", puis nous les remplaçons par la partie entre les "" et entourez ceci de> <.
De Greg H., j'ai pu créer cette expression régulière pour répondre à mes besoins.
J'avais besoin de faire correspondre une valeur spécifique qualifiée en étant entre guillemets. Il doit s'agir d'une correspondance complète, aucune correspondance partielle ne devrait déclencher un hit
Par exemple, "test" ne peut pas correspondre à "test2".
reg = r"""(['"])(%s)\1"""
if re.search(reg%(needle), haystack, re.IGNORECASE):
print "winning..."
chasseur
Si vous essayez de trouver des chaînes qui n'ont qu'un certain suffixe, comme la syntaxe à points, vous pouvez essayer ceci:
\"([^\"]*?[^\"]*?)\".localized
Où .localized
est le suffixe.
Exemple:
print("this is something I need to return".localized + "so is this".localized + "but this is not")
Il capturera "this is something I need to return".localized
et "so is this".localized
non "but this is not"
.
Une réponse supplémentaire pour le sous-ensemble de codeurs Microsoft VBA, un seul utilise la bibliothèque Microsoft VBScript Regular Expressions 5.5
et cela donne le code suivant
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
Pour moi a travaillé celui-ci:
|([\'"])(.*?)\1|i
J'ai utilisé dans une phrase comme celle-ci:
preg_match_all('|([\'"])(.*?)\1|i', $cont, $matches);
et cela a très bien fonctionné.
Toutes les réponses ci-dessus sont bonnes .... sauf qu'elles ne prennent pas en charge tous les caractères unicode! à ECMA Script (Javascript)
Si vous êtes un utilisateur de nœud, vous souhaiterez peut-être la version modifiée de la réponse acceptée qui prend en charge tous les caractères unicode:
/(?<=((?<=[\s,.:;"']|^)["']))(?:(?=(\\?))\2.)*?(?=\1)/gmu
Essayez ici .
? The preceding token is not quantifiable