web-dev-qa-db-fra.com

Expression régulière pour obtenir une chaîne entre deux chaînes en Javascript

J'ai trouvé des articles très similaires, mais je n'arrive pas à comprendre mon expression régulière ici.

J'essaie d'écrire une expression régulière qui renvoie une chaîne située entre deux autres chaînes. Par exemple: je veux obtenir la chaîne qui réside entre les chaînes "vache" et "lait".

Ma vache donne toujours du lait

retournerais

"donne toujours"

Voici l'expression que j'ai reconstituée jusqu'à présent:

(?=cow).*(?=milk)

Cependant, cela retourne la chaîne "vache donne toujours".

131
phil

Un lookahead (cette partie (?=) ne consomme aucune entrée. C'est un assertion de largeur nulle (comme le sont les vérifications de limites et les recherches).

Vous voulez une correspondance régulière ici, pour consommer la portion cow. Pour capturer la partie intermédiaire, vous utilisez un groupe de capture (placez simplement la partie du motif que vous souhaitez capturer entre parenthèses):

cow(.*)milk

Aucun coup d'oeil n'est nécessaire du tout.

153

Expression régulière pour obtenir une chaîne entre deux chaînes en JavaScript

La solution la plus complète qui fonctionne dans la plupart des cas consiste à utiliser un groupe de capture avec un correspondance de points paresseux. motif . Cependant, un point . dans une expression rationnelle JavaScript ne correspond pas aux caractères de saut de ligne. Ainsi, dans 100% des cas, un [^] ou [\s\S]/[\d\D]/[\w\W] construit.

ECMAScript 2018 et solution compatible plus récente

Dans les environnements JavaScript prenant en charge ECMAScript 2018 , le modificateur s permet à . de faire correspondre tout caractère, y compris les caractères de fin de ligne, et le moteur des expressions régulières prend en charge les contours de longueur variable. Donc, vous pouvez utiliser une regex comme

var result = s.match(/(?<=cow\s+).*?(?=\s+milk)/gs); // Returns multiple matches if any
// Or
var result = s.match(/(?<=cow\s*).*?(?=\s*milk)/gs); // Same but whitespaces are optional

Dans les deux cas, la position actuelle est vérifiée pour cow avec tout espacement égal ou supérieur à 1/0 après cow, puis tous les caractères 0+ aussi peu que possible sont appariés et consommés (= ajouté à la valeur de correspondance ), puis milk est vérifié (avec tout espacement 1/0 ou plus avant cette sous-chaîne).

Scénario 1: Saisie sur une seule ligne

Ce scénario et tous les autres scénarios ci-dessous sont pris en charge par tous les environnements JavaScript. Voir les exemples d'utilisation au bas de la réponse.

cow (.*?) milk

cow est trouvé en premier, puis un espace, puis tous les caractères 0+ autres que les caractères de fin de ligne, aussi peu que possible, car *? est un quantificateur paresseux, sont capturés dans le groupe 1, puis dans un espace avec milk doit suivre (et ceux-ci sont appariés et consommés aussi).

Scénario 2: entrée multiligne

cow ([\s\S]*?) milk

Ici, cow et un espace sont mis en correspondance en premier, puis tous les caractères 0+ aussi peu que possible sont mis en correspondance et capturés dans le groupe 1, puis un espace avec milk en correspondance.

Scénario 3: matchs qui se chevauchent

Si vous avez une chaîne du type >>>15 text>>>67 text2>>> et qu'il vous faut 2 correspondances entre >>> + number + whitespace et >>>, vous ne pouvez pas utiliser />>>\d+\s(.*?)>>>/g car cela ne trouvera qu'une correspondance car le >>> avant 67 est déjà consommé lors de la recherche du premier rencontre. Vous pouvez utiliser un lookahead positif pour vérifier la présence du texte sans réellement le "gober" (c'est-à-dire l'ajouter à la correspondance). :

/>>>\d+\s(.*?)(?=>>>)/g

Voir le démonstration en ligne regex donnant text1 et text2 en tant que contenu du groupe 1 trouvé.

Voir aussi Comment obtenir toutes les correspondances possibles pour une chaîne .

Considérations de performance

Un modèle de correspondance de points paresseux (.*?) dans les modèles regex peut ralentir l'exécution du script si une très longue entrée est donnée. Dans de nombreux cas, la technique de dérouler la boucle est plus utile. En essayant de tout saisir entre cow et milk à partir de "Their\ncow\ngives\nmore\nmilk", nous voyons qu'il faut juste faire correspondre toutes les lignes qui ne commencent pas par milk, donc au lieu de - cow\n([\s\S]*?)\nmilk on peut utiliser:

/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm

Voir le démo regex (s'il peut y avoir \r\n, utilisez /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm). Avec cette petite chaîne de test, le gain de performance est négligeable, mais avec un texte très volumineux, vous sentirez la différence (surtout si les lignes sont longues et que les sauts de ligne ne sont pas très nombreux).

Exemple d'utilisation de regex en JavaScript:

//Single/First match expected: use no global modifier and access match[1]
console.log("My cow always gives milk".match(/cow (.*?) milk/)[1]);
// Multiple matches: get multiple matches with a global modifier and
// trim the results if length of leading/trailing delimiters is known
var s = "My cow always gives milk, thier cow also gives milk";
console.log(s.match(/cow (.*?) milk/g).map(function(x) {return x.substr(4,x.length-9);}));
//or use RegExp#exec inside a loop to collect all the Group 1 contents
var result = [], m, rx = /cow (.*?) milk/g;
while ((m=rx.exec(s)) !== null) {
  result.Push(m[1]);
}
console.log(result);
55
Wiktor Stribiżew

Voici une regex qui saisira le lien entre vache et lait (sans espace de début/fin):

srctext = "My cow always gives milk.";
var re = /(.*cow\s+)(.*)(\s+milk.*)/;
var newtext = srctext.replace(re, "$2");

Un exemple: http://jsfiddle.net/entropo/tkP74/

50
entropo
  • Vous devez capturer le .*
  • Vous pouvez (mais ce n’est pas obligatoire) faire le .* non-comique
  • Il n'y a vraiment pas besoin de regarder avant.

    > /cow(.*?)milk/i.exec('My cow always gives milk');
    ["cow always gives milk", " always gives "]
    
15
Matt Ball

J'ai pu obtenir ce dont j'avais besoin en utilisant la solution de Martinho Fernandes ci-dessous. Le code est:

var test = "My cow always gives milk";

var testRE = test.match("cow(.*)milk");
alert(testRE[1]);

Vous remarquerez que je préviens la variable testRE sous forme de tableau. En effet, testRE revient sous forme de tableau, pour une raison quelconque. La sortie de:

My cow always gives milk

Transforme en:

always gives
7
phil

La réponse choisie n'a pas fonctionné pour moi ... hmm ...

Il suffit d’ajouter de l’espace après la vache et/ou avant le lait pour réduire les espaces "toujours"

/(?<=cow ).*(?= milk)/

enter image description here

6
duduwe

Utilisez simplement l'expression régulière suivante:

(?<=My cow\s).*?(?=\smilk)
4
Brandon

La méthode match () recherche une correspondance dans une chaîne et renvoie un objet Array.

// Original string
var str = "My cow always gives milk";

// Using index [0] would return<br/>
// "**cow always gives milk**"
str.match(/cow(.*)milk/)**[0]**


// Using index **[1]** would return
// "**always gives**"
str.match(/cow(.*)milk/)[1]
0
Marc Antoni