Expressão regular para obter uma cadeia entre duas cadeias de caracteres em JavaScript

Eu encontrei posts muito parecidos, mas não consigo ter minha expressão regular aqui.

Eu estou tentando escrever uma expressão regular que retorna uma seqüência de caracteres que é entre duas outras seqüências de caracteres. Por exemplo: eu quero pegar a string que reside entre as cordas “vaca” e “leite”

Minha vaca sempre dá leite

retornaria

“sempre dá”

Aqui está a expressão que eu juntei até agora:

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

No entanto, isso retorna a string “vaca sempre dá”

Um lookahead (que (?= Parte) não consome nenhuma input. É uma asserção de largura zero (assim como as verificações de limite e lookbehinds).

Você quer um jogo regular aqui, para consumir a porção de cow . Para capturar a porção intermediária, use um grupo de captura (basta colocar a parte do padrão que você deseja capturar entre parênteses):

 cow(.*)milk 

Nenhum lookaheads é necessário a todos.

Aqui está uma regex que vai pegar o que há entre vaca e leite (sem espaço à esquerda / à esquerda):

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

Um exemplo: http://jsfiddle.net/entropo/tkP74/

Expressão regular para obter uma cadeia entre duas cadeias de caracteres em JavaScript

A solução mais completa que funcionará na grande maioria dos casos é usar um grupo de captura com um padrão de correspondência de pontos preguiçosos . No entanto, um ponto . em regex JS não corresponde a caracteres de quebra de linha, então, o que funcionará em 100% casos é uma construção [^] ou [\s\S] / [\d\D] / [\w\W] .

ECMAScript 2018 e nova solução compatível

Em ambientes JS, o suporte ao modificador ECMAScript 2018 permite . para corresponder a qualquer caractere, incluindo caracteres de quebra de linha, e o mecanismo regex suporta lookbehinds de tamanho variável. Então, você pode usar um regex 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 

Em ambos os casos, a posição atual é checada para cow com qualquer 1/0 ou mais espaços em branco após cow , então quaisquer 0+ caracteres o mínimo possível são combinados e consumidos (= adicionado ao valor de correspondência), e então o milk é checado (com qualquer 1/0 ou mais espaços em branco antes dessa subseqüência).

Cenário 1: input de linha única

Este e todos os outros cenários abaixo são suportados por todos os ambientes JS. Veja exemplos de uso na parte inferior da resposta.

 cow (.*?) milk 

cow é encontrada primeiro, depois um espaço, então qualquer 0 + chars diferente de chars de quebra de linha, o mínimo possível como *? é um quantificador preguiçoso, são capturados no Grupo 1 e, em seguida, um espaço com milk deve seguir (e esses também são combinados e consumidos ).

Cenário 2: Entrada Multiline

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

Aqui, cow e um espaço são combinados primeiro, então qualquer 0+ chars o mínimo possível são combinados e capturados no Grupo 1, e então um espaço com milk é correspondido.

Cenário 3: coincidências sobrepostas

Se você tiver uma string como >>>15 text>>>67 text2>>> e precisar obter 2 correspondências entre >>> + number + whitespace e >>> , não será possível usar />>>\d+\s(.*?)>>>/g pois isso só encontrará 1 correspondência devido ao fato de que o >>> anterior a 67 já foi consumido ao encontrar a primeira correspondência. Você pode usar um lookahead positivo para verificar a presença de texto sem realmente "devorar" (ou seja, acrescentar ao jogo):

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

Veja a demo regex on - line gerando text1 e text2 como o conteúdo do Grupo 1 encontrado.

Veja também Como obter todas as possíveis correspondências sobrepostas para uma string .

Considerações de desempenho

Padrão de correspondência de ponto preguiçoso ( .*? ) Dentro de padrões de regex pode diminuir a execução do script se uma input muito longa for fornecida. Em muitos casos, a técnica de unroll-loop ajuda em maior medida. Tentando pegar tudo entre cow e milk de "Their\ncow\ngives\nmore\nmilk" , vemos que só precisamos combinar todas as linhas que não começam com milk , assim, ao invés de cow\n([\s\S]*?)\nmilk podemos usar:

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

Veja a demo regex (se pode haver \r\n , use /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm ). Com essa pequena cadeia de teste, o ganho de desempenho é insignificante, mas com um texto muito grande, você sentirá a diferença (especialmente se as linhas forem longas e as quebras de linha não forem muito numerosas).

Exemplo de uso de regex em 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); 
  • Você precisa capturar o .*
  • Você pode (mas não precisa) fazer o .* Nongreedy
  • Não há realmente nenhuma necessidade para o lookahead.

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

Consegui o que precisava usando a solução de Martinho Fernandes abaixo. O código é:

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

Você notará que estou alertando a variável testRE como uma matriz. Isso ocorre porque o testRE está retornando como uma matriz, por algum motivo. A saída de:

 My cow always gives milk 

Muda para:

 always gives 

Que tal apenas usando a seguinte expressão regular:

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

A resposta escolhida não funcionou para mim … hmm …

Basta adicionar espaço após a vaca e / ou antes do leite para aparar espaços de “sempre dá”

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

insira a descrição da imagem aqui

O método match () pesquisa uma string por uma correspondência e retorna um object Array.

 // Original string var str = "My cow always gives milk"; // Using index [0] would return
// "**cow always gives milk**" str.match(/cow(.*)milk/)**[0]** // Using index **[1]** would return // "**always gives**" str.match(/cow(.*)milk/)[1]