Expresión regular para obtener una cadena entre dos cadenas en Javascript

166

He encontrado publicaciones muy similares, pero no puedo obtener mi expresión regular aquí.

Estoy tratando de escribir una expresión regular que devuelve una cadena que se encuentra entre otras dos cadenas. Por ejemplo: quiero obtener la cadena que reside entre las cadenas "vaca" y "leche".

Mi vaca siempre da leche

volvería

"siempre da"

Aquí está la expresión que he juntado hasta ahora:

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

Sin embargo, esto devuelve la cadena "vaca siempre da".

phil
fuente
66
Me topé con esta vieja pregunta y quería aclarar por qué testRE es una matriz. test.match devuelve una matriz con el primer índice como la coincidencia total (por lo tanto, la cadena que coincide con la leche de vaca (. *)) y luego, todas las cadenas atrapadas como (. *) si hubiera un segundo conjunto de paréntesis que lo harían luego estar en testRE [2]
Salketer
44
Esta solución no funcionará si está buscando en una cadena que contiene nuevas líneas. En tal caso, debe usar "STRING_ONE ([\\ s \\ S] *?) STRING_TWO". stackoverflow.com/questions/22531252/…
Michael.Lumley
solo como referencia el método de coincidencia en MDN developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
vzR

Respuestas:

183

Una búsqueda anticipada (esa (?=parte) no consume ninguna entrada. Es una afirmación de ancho cero (al igual que las comprobaciones de límites y las miradas posteriores).

Desea una coincidencia regular aquí, para consumir la cowporción. Para capturar la parte intermedia, utiliza un grupo de captura (solo coloca la parte del patrón que deseas capturar entre paréntesis):

cow(.*)milk

No se necesitan lookaheads en absoluto.

R. Martinho Fernandes
fuente
26
Cuando pruebo esto, la expresión Regex proporcionada incluye "vaca" y "leche" ...
TheCascadian
44
A este le falta un paso. Cuando obtiene el resultado de la coincidencia, debe extraer el texto coincidente del primer grupo de captura con matched[1], no todo el texto coincidente con matched[0].
Rory O'Kane
77
En Javascript, en realidad necesita usar en ([\s\S]*?)lugar de (.*?).
Qian Chen
77
Aunque esta es una técnica útil, fue rechazada porque, en mi humilde opinión, esta NO es la respuesta correcta para la pregunta, ya que incluye "vaca" y "leche", según lo declarado por @TheCascadian
Almir Campos
@AlmirCampos: si no me equivoco, no hay forma de hacer esta combinación sin hacer coincidir "vaca" y "leche" (ya que desea hacer coincidir lo que hay entre esas dos). El problema no está en el propio RegEx sino en cómo lo manejas después (como mencionó Rory O'Kane). De lo contrario, solo podría coincidir con los espacios circundantes, y eso le daría un retorno MUY incorrecto, ¿no?
nacido
69

Expresión regular para obtener una cadena entre dos cadenas en JavaScript

La solución más completa que funcionará en la gran mayoría de los casos es usar un grupo de captura con un patrón de coincidencia de puntos diferidos . Sin embargo, un punto .en JavaScript expresión regular no coincide con caracteres de salto de línea, por lo que, lo que va a funcionar en 100% de los casos es un [^]o [\s\S]/ [\d\D]/ [\w\W]construcciones.

ECMAScript 2018 y una solución compatible más nueva

En entornos JavaScript que admiten ECMAScript 2018 , el smodificador permite .hacer coincidir cualquier carácter, incluidos los caracteres de salto de línea, y el motor regex admite retrospectivas de longitud variable. Entonces, puedes usar una expresión regular como

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

En ambos casos, la posición actual se verifica cowcon cualquier 1/0 o más espacios en blanco después cow, luego se iguala y consume cualquier carácter de 0+ lo menos posible (= agregado al valor de coincidencia), y luego milkse verifica (con cualquier 1/0 o más espacios en blanco antes de esta subcadena).

Escenario 1: entrada de línea única

Este y todos los demás escenarios a continuación son compatibles con todos los entornos JavaScript. Ver ejemplos de uso al final de la respuesta.

cow (.*?) milk

cowse encuentra en primer lugar, a continuación, un espacio, entonces cualquier 0+ caracteres distintos de caracteres de salto de línea, tan pocos como sea posible como *?es un cuantificador perezoso, son capturados en el Grupo 1 y luego un espacio con milkdebe seguir (y aquellos se emparejan y consume , también )

Escenario 2: entrada multilínea

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

Aquí, cowy se hace coincidir un espacio primero, luego se combinan los caracteres 0+ lo menos posible y se capturan en el Grupo 1, y luego milkse hace coincidir un espacio con .

Escenario 3: coincidencias superpuestas

Si tiene una cadena como >>>15 text>>>67 text2>>>y necesita obtener 2 coincidencias entre >>>+ number+ whitespacey >>>, no puede usar, />>>\d+\s(.*?)>>>/gya que esto solo encontrará 1 coincidencia debido a que el >>>anterior 67ya se consume al encontrar la primera coincidencia. Puede utilizar una búsqueda anticipada positiva para verificar la presencia del texto sin realmente "engullirlo" (es decir, agregarlo a la coincidencia):

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

Vea el rendimiento de la demostración de expresiones regulares en líneatext1 y los text2contenidos del Grupo 1 encontrados.

Consulte también Cómo obtener todas las coincidencias superpuestas posibles para una cadena .

Consideraciones de rendimiento

El patrón de coincidencia de puntos diferidos ( .*?) dentro de los patrones de expresiones regulares puede ralentizar la ejecución del script si se proporciona una entrada muy larga. En muchos casos, la técnica de desenrollar el bucle ayuda en mayor medida. Intentando tomar todo entre cowy milkdesde "Their\ncow\ngives\nmore\nmilk", vemos que solo necesitamos unir todas las líneas que no comienzan milk, por lo tanto, en lugar de cow\n([\s\S]*?)\nmilkpoder usar:

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

Vea la demostración de expresiones regulares (si puede haberla \r\n, úsela /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm). Con esta pequeña cadena de prueba, la ganancia de rendimiento es insignificante, pero con un texto muy grande, sentirá la diferencia (especialmente si las líneas son largas y los saltos de línea no son muy numerosos).

Ejemplo de uso de expresiones regulares 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);

Usando el String#matchAllmétodo moderno

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
fuente
51

Aquí hay una expresión regular que captará lo que hay entre la vaca y la leche (sin espacio inicial / final):

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

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

entropo
fuente
17
  • Necesitas capturar el .*
  • Puedes (pero no tienes que hacerlo) hacer la no .*codicia
  • Realmente no hay necesidad de mirar hacia adelante.

    > /cow(.*?)milk/i.exec('My cow always gives milk');
    ["cow always gives milk", " always gives "]
Matt Ball
fuente
En este caso particular, si fuera codicioso llegaría al final y retrocedería (presumiblemente).
Ben
9

La respuesta elegida no funcionó para mí ... hmm ...

Simplemente agregue espacio después de la vaca y / o antes de la leche para recortar espacios de "siempre da"

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

ingrese la descripción de la imagen aquí

duduwe
fuente
No necesita comentar su propia respuesta, solo edítela.
Cody G
Look Behind ?<=no es compatible con Javascript.
Mark Carpenter Jr
@ MarkCarpenterJr si lo probó a través de regextester.com , obtendrá esa pista. Parece que el sitio ha basado sus reglas de la especificación anterior. Lookbehind ahora es compatible. Consulte stackoverflow.com/questions/30118815/… Y el patrón funciona bien con los navegadores modernos sin error. Pruebe este corrector en su
duduwe
@ CodyG.ah sí. Entendido.
duduwe
8

Pude obtener lo que necesitaba usando la solución de Martinho Fernandes a continuación. El codigo es:

var test = "My cow always gives milk";

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

Notarás que estoy alertando a la variable testRE como una matriz. Esto se debe a que testRE está regresando como una matriz, por alguna razón. La salida de:

My cow always gives milk

Cambios en:

always gives
phil
fuente
1
Gracias, agregué un violín ( jsfiddle.net/MoscaPt/g5Lngjx8/2 ) para ello. / Johan
Mosca Pt
4

Simplemente use la siguiente expresión regular:

(?<=My cow\s).*?(?=\smilk)
Brandon
fuente
Look Behind ?<=no es compatible con Javascript. Sin embargo, sería la forma de hacerlo.
Mark Carpenter Jr
Es compatible con JavaScript. No es compatible con Safari y Mozilla (todavía), solo en Chrome y Opera.
Paul Strupeikis
3

Encuentro que la expresión regular es tediosa y consume mucho tiempo dada la sintaxis. Como ya está usando JavaScript, es más fácil hacer lo siguiente sin 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
fuente
2
¡Funciona para mi! respuesta fantástica porque es realmente simple! :)
Andrew Irwin
2

Si los datos están en varias líneas, es posible que deba usar lo siguiente

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

My cow always gives 
milk

Ejemplo de Regex 101

Naresh Kumar
fuente
0

El método match () busca una cadena para una coincidencia y devuelve un objeto 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
fuente
0

Tarea

Extraiga la subcadena entre dos cadenas (excluyendo estas dos cadenas)

Solución

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
fuente