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

166

J'ai trouvé des articles très similaires, mais je ne peux pas tout à fait obtenir mon expression régulière ici.

J'essaye d'écrire une expression régulière qui renvoie une chaîne qui se trouve entre deux autres chaînes. Par exemple: je veux obtenir la chaîne qui se trouve 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 renvoie la chaîne "la vache donne toujours".

phil
la source
6
Je suis tombé sur cette vieille question et je voulais clarifier pourquoi testRE est un tableau. test.match renvoie un tableau avec le premier index comme correspondance totale (pour cela, la chaîne qui correspond au lait de vache (. *)) et ensuite, toutes les chaînes piégées comme le (. *) s'il y avait un deuxième ensemble de parenthèses, ils le feraient alors soyez dans testRE [2]
Salketer
4
Cette solution ne fonctionnera pas si vous recherchez une chaîne contenant des sauts de ligne. Dans ce cas, vous devez utiliser "STRING_ONE ([\\ s \\ S] *?) STRING_TWO". stackoverflow.com/questions/22531252/…
Michael.Lumley
juste pour référence la méthode de correspondance sur MDN developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
vzR

Réponses:

183

Une anticipation (cette (?=partie) ne consomme aucune entrée. Il s'agit d'une assertion de largeur nulle (tout comme les vérifications de limites et les regards en arrière).

Vous voulez un match régulier ici, pour consommer la cowportion. Pour capturer la partie intermédiaire, vous utilisez un groupe de capture (mettez simplement la partie du motif que vous souhaitez capturer entre parenthèses):

cow(.*)milk

Aucun lookahead n'est nécessaire du tout.

R. Martinho Fernandes
la source
26
Quand je teste cela, l'expression Regex fournie comprend à la fois «vache» et «lait» ...
TheCascadian
4
Il manque une étape. Lorsque vous obtenez le résultat de la correspondance, vous devez extraire le texte correspondant du premier groupe de capture avec matched[1], et non tout le texte correspondant avec matched[0].
Rory O'Kane
7
En Javascript, vous devez en fait utiliser ([\s\S]*?)plutôt que (.*?).
Qian Chen
7
Bien que ce soit une technique utile, elle a été rejetée car à mon humble avis, ce n'est PAS la bonne réponse à la question, car elle comprend «vache» et «lait», comme indiqué par @TheCascadian
Almir Campos
@AlmirCampos - si je ne me trompe pas, il n'y a aucun moyen de faire cette correspondance sans faire correspondre «vache» et «lait» (puisque vous voulez faire correspondre ce qui se trouve entre ces deux). Le problème n'est pas dans le RegEx lui-même mais comment vous le gérez par la suite (comme mentionné par Rory O'Kane). Sinon, vous ne pourriez faire correspondre que les espaces environnants - et cela vous donnerait un TRÈS mauvais retour, n'est-ce pas?
sborn
69

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

La solution la plus complète qui fonctionnera dans la grande majorité des cas utilise un groupe de capture avec un modèle de correspondance de points paresseux . Cependant, un point .dans l'expression régulière JavaScript ne correspond pas aux caractères de saut de ligne, donc, ce qui fonctionnera dans 100% des cas est une construction [^]ou [\s\S]/ [\d\D]/ [\w\W].

ECMAScript 2018 et solution compatible plus récente

Dans les environnements JavaScript prenant en charge ECMAScript 2018 , le smodificateur permet de .faire correspondre n'importe quel caractère, y compris les caractères de saut de ligne, et le moteur regex prend en charge les lookbehinds de longueur variable. Donc, vous pouvez utiliser une expression régulière 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 cowavec n'importe quel 1/0 ou plus d'espaces blancs après cow, puis tous les caractères 0+ aussi peu que possible sont mis en correspondance et consommés (= ajouté à la valeur de correspondance), puis milkest vérifié (avec n'importe quel 1/0 ou plus d'espaces blancs avant cette sous-chaîne).

Scénario 1: entrée 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 des exemples d'utilisation au bas de la réponse.

cow (.*?) milk

cowse trouve d' abord, puis un espace, puis tout 0+ caractères autres que les caractères de saut de ligne, aussi peu que possible *?est un quantificateur paresseux, sont capturés dans le Groupe 1, puis un espace avec milksuivi incontournable (et ceux qui sont en correspondance et consommaient aussi ).

Scénario 2: entrée multiligne

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

Ici, cowet un espace est 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 milksont mis en correspondance.

Scénario 3: correspondances qui se chevauchent

Si vous avez une chaîne comme >>>15 text>>>67 text2>>>et que vous avez besoin d'obtenir 2 correspondances entre >>>+ number+ whitespaceet >>>, vous ne pouvez pas l'utiliser />>>\d+\s(.*?)>>>/gcar cela ne trouvera qu'une seule correspondance car l' >>>avant 67est déjà consommé lors de la recherche de la première correspondance. Vous pouvez utiliser une anticipation positive pour vérifier la présence du texte sans réellement «l'avaler» (c'est-à-dire l'ajouter à la correspondance):

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

Voir la démo en ligne regex rendement text1et du text2groupe 1 contenus trouvés.

Consultez également Comment obtenir toutes les correspondances qui se chevauchent pour une chaîne .

Considérations relatives aux performances

Le motif de correspondance de points paresseux ( .*?) à l'intérieur des modèles de regex peut ralentir l'exécution du script si une entrée très longue est donnée. Dans de nombreux cas, la technique du déroulement de la boucle aide dans une plus grande mesure. En essayant de saisir tout entre cowet milkdepuis "Their\ncow\ngives\nmore\nmilk", nous voyons que nous avons juste besoin de faire correspondre toutes les lignes qui ne commencent pas par milk, donc, au lieu de cow\n([\s\S]*?)\nmilknous pouvons utiliser:

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

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

Exemple d'utilisation de regex dans 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);

Utiliser la String#matchAllméthode moderne

const s = "My cow always gives milk, thier cow also gives milk";
const matches = s.matchAll(/cow (.*?) milk/g);
console.log(Array.from(matches, x => x[1]));

Wiktor Stribiżew
la source
51

Voici une expression régulière qui saisira ce qui se trouve entre la vache et le lait (sans espace de début / de 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/

entropo
la source
17
  • Vous devez capturer le .*
  • Vous pouvez (mais ne devez pas) faire le .*non
  • 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 "]
    
Matt Ball
la source
Dans ce cas particulier, s'il était avide, il atteindrait la fin et ferait marche arrière (vraisemblablement).
Ben
9

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

Ajoutez simplement de l'espace après la vache et / ou avant le lait pour couper les espaces de "donne toujours"

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

entrez la description de l'image ici

duduwe
la source
Vous n'avez pas besoin de commenter votre propre réponse, modifiez-la simplement.
Cody G
Look Behind ?<=n'est pas pris en charge en Javascript.
Mark Carpenter Jr
@MarkCarpenterJr si vous l'avez testé via regextester.com , vous obtiendrez cet indice. Il semble que le site ait basé ses règles sur l'ancienne spécification. Lookbehind est désormais pris en charge. Voir stackoverflow.com/questions/30118815/... Et le modèle fonctionne bien avec les navigateurs modernes sans erreur. Essayez plutôt ce vérificateur regex101.com
duduwe
@ CodyG.ah oui. je l'ai.
duduwe
8

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 j'alerte la variable testRE sous forme de tableau. C'est parce que testRE revient sous forme de tableau, pour une raison quelconque. La sortie de:

My cow always gives milk

Se transforme en:

always gives
phil
la source
1
Merci, j'ai ajouté un violon ( jsfiddle.net/MoscaPt/g5Lngjx8/2 ) pour cela. / Johan
Mosca Pt
4

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

(?<=My cow\s).*?(?=\smilk)
Brandon
la source
Look Behind ?<=n'est pas pris en charge en Javascript. Ce serait le moyen de le faire cependant.
Mark Carpenter Jr
Il est pris en charge en JavaScript. Il n'est pas pris en charge dans Safari et Mozilla (encore), uniquement dans Chrome et Opera.
Paul Strupeikis
4

Je trouve que l'expression régulière est fastidieuse et prend du temps compte tenu de la syntaxe. Puisque vous utilisez déjà javascript, il est plus facile de faire ce qui suit sans regex:

const text = 'My cow always gives milk'
const start = `cow`;
const end = `milk`;
const middleText = text.split(start)[1].split(end)[0]
console.log(middleText) // prints "always gives"
Chase Oliphant
la source
2
Travaille pour moi! réponse fantastique parce que c'est vraiment simple! :)
Andrew Irwin le
2

Si les données sont sur plusieurs lignes, vous devrez peut-être utiliser ce qui suit,

/My cow ([\s\S]*)milk/gm

My cow always gives 
milk

Exemple Regex 101

Naresh Kumar
la source
0

La méthode match () recherche une chaîne pour une correspondance 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]
Marc Antoni
la source
0

Tâche

Extraire la sous-chaîne entre deux chaînes (à l'exclusion de ces deux chaînes)

Solution

let allText = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum";
let textBefore = "five centuries,";
let textAfter = "electronic typesetting";
var regExp = new RegExp(`(?<=${textBefore}\\s)(.+?)(?=\\s+${textAfter})`, "g");
var results = regExp.exec(allText);
if (results && results.length > 1) {
    console.log(results[0]);
}
Vasily Bodnarchuk
la source