Expressão regular para obter uma string entre duas strings em Javascript

166

Eu encontrei posts muito semelhantes, mas não consigo entender minha expressão regular aqui.

Eu estou tentando escrever uma expressão regular que retorna uma string que está entre duas outras strings. Por exemplo: eu quero obter a string que reside entre as strings "cow" e "milk".

Minha vaca sempre dá leite

retornaria

"sempre dá"

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

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

No entanto, isso retorna a string "vaca sempre dá".

phil
fonte
6
Eu me deparei com essa pergunta antiga e queria esclarecer por que o testRE é uma matriz. test.match retorna uma matriz com o primeiro índice como a correspondência total (portanto, a string que corresponde ao leite de vaca (. *)) e, em seguida, todas as strings capturadas como o (. *) se houvesse um segundo conjunto de parênteses. então esteja em testRE [2]
Salketer 6/13/13
4
Esta solução não funcionará se você estiver pesquisando sobre uma sequência contendo novas linhas. Nesse caso, você deve usar "STRING_ONE ([\\ s \\ S] *?) STRING_TWO". stackoverflow.com/questions/22531252/…
Michael.Lumley
apenas para referência ao método de correspondência no MDN developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
vzR

Respostas:

183

Um lookahead (essa (?=parte) não consome nenhuma entrada. É uma asserção de largura zero (assim como verificações de limites e visões atrás).

Você deseja uma correspondência regular aqui, para consumir a cowparte. Para capturar a parte intermediária, use um grupo de captura (basta colocar a parte do padrão que você deseja capturar entre parênteses):

cow(.*)milk

Nenhum lookahead é necessário.

R. Martinho Fernandes
fonte
26
Quando eu testar isso, a expressão Regex fornecido inclui tanto "vaca" e "leite" ...
TheCascadian
4
Está faltando um passo. Quando você obtém o resultado da correspondência, precisa extrair o texto correspondente do primeiro grupo de captura matched[1], e não todo o texto correspondente matched[0].
Rory O'Kane
7
Em Javascript, você realmente precisa usar em ([\s\S]*?)vez de (.*?).
Qian Chen
7
Embora esta seja uma techique útil, ele foi downvoted porque IMHO esta não é a resposta certa para a pergunta, pois inclui a "vaca" e "leite", como afirma @TheCascadian
Almir Campos
@AlmirCampos - se não me engano, não há como fazer essa partida sem combinar "vaca" e "leite" (já que você deseja combinar o que há entre os dois). O problema não está no RegEx propriamente dito, mas em como você lida com isso posteriormente (como mencionado por Rory O'Kane). Caso contrário, você só poderia corresponder aos espaços ao redor - e isso daria um retorno MUITO errado, não?
nascida
69

Expressão regular para obter uma string entre duas strings 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 JavaScript regex não coincide com caracteres de quebra de linha, por isso, o que vai funcionar em 100% dos casos é um [^]ou [\s\S]/ [\d\D]/ [\w\W]construções.

ECMAScript 2018 e mais recente solução compatível

Nos ambientes JavaScript que suportam o ECMAScript 2018 , o smodificador permite .corresponder qualquer caractere, incluindo caracteres de quebra de linha, e o mecanismo regex suporta lookbehinds de comprimento 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 é verificada cowcom 1/0 ou mais espaços em branco depois e cow, em seguida, quaisquer 0 ou mais caracteres possíveis são correspondidos e consumidos (= adicionados ao valor da correspondência) e, em seguida, milkverificados (com qualquer 1/0 ou mais espaços em branco antes dessa substring).

Cenário 1: Entrada de linha única

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

cow (.*?) milk

cowé encontrado em primeiro lugar, em seguida, um espaço, em seguida, quaisquer outros do que caracteres de quebra de linha 0+ caracteres, o menor número possível como *?é um quantificador preguiçoso, são capturados em Grupo 1 e, em seguida, um espaço com milkdeve seguir (e aqueles são combinados e consumidos , também )

Cenário 2: Entrada multilinha

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

Aqui, cowe um espaço é correspondido primeiro, em seguida, quaisquer 0 + caracteres o menor possível são correspondidos e capturados no Grupo 1 e, em seguida, um espaço milké correspondido.

Cenário 3: correspondências sobrepostas

Se você tem uma string como essa >>>15 text>>>67 text2>>>e precisa obter duas correspondências entre >>>+ number+ whitespacee >>>, não pode usá-la, />>>\d+\s(.*?)>>>/gpois isso encontrará apenas 1 correspondência, porque o >>>antes 67já foi consumido ao encontrar a primeira correspondência. Você pode usar um lookahead positivo para verificar a presença do texto sem "devorá-lo" (por exemplo, acrescentando à correspondência):

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

Veja a regex demonstração online rendendo text1e text2como Grupo 1 conteúdos encontrados.

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

Considerações de desempenho

O padrão de correspondência de pontos preguiçosos ( .*?) dentro dos padrões regex pode retardar a execução do script se for fornecida uma entrada muito longa. Em muitos casos, a técnica de desenrolar o loop ajuda em maior extensão. Tentando pegar tudo entre cowe milkde "Their\ncow\ngives\nmore\nmilk", vemos que precisamos apenas corresponder a todas as linhas que não começam milk, portanto, em vez de cow\n([\s\S]*?)\nmilkpodermos usar:

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

Veja a demonstração do regex (se possível \r\n, use /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm). Com essa pequena sequência 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);

Usando o 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
fonte
51

Aqui está um regex que captura o que há entre vaca e leite (sem espaço à esquerda / à direita):

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/

entropo
fonte
17
  • Você precisa capturar o .*
  • Você pode (mas não precisa) fazer o não- .*remédio
  • Realmente não há necessidade de olhar para trás.

    > /cow(.*?)milk/i.exec('My cow always gives milk');
    ["cow always gives milk", " always gives "]
Matt Ball
fonte
Nesse caso em particular, se fosse ganancioso, chegaria ao fim e recuaria (presumivelmente).
21411 Ben
9

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

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

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

insira a descrição da imagem aqui

duduwe
fonte
Você não precisa comentar sua própria resposta, basta editá-la.
Cody L
Look Behind ?<=não é suportado em Javascript.
Mark-Carpenter Jr
@MarkCarpenterJr Se você o testou via regextester.com , você receberá essa dica. Parece que o site baseou suas regras na especificação mais antiga. Lookbehind agora é suportado. Consulte stackoverflow.com/questions/30118815/… E o padrão funciona bem com navegadores modernos sem erros. Tente este verificador em vez disso, regex101.com
duduwe 8/8
@ CodyG.ah sim. Entendi.
duduwe
8

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 testRE está retornando como uma matriz, por algum motivo. A saída de:

My cow always gives milk

Alterações para:

always gives
phil
fonte
1
Obrigado, eu adicionei um violino ( jsfiddle.net/MoscaPt/g5Lngjx8/2 ) por ele. / Johan
Mosca Pt
4

Basta usar a seguinte expressão regular:

(?<=My cow\s).*?(?=\smilk)
Brandon
fonte
Look Behind ?<=não é suportado em Javascript. Seria o caminho para fazê-lo embora.
Mark-Carpenter Jr
É suportado em JavaScript. Ainda não é suportado no Safari e Mozilla, apenas no Chrome e Opera.
Paul Strupeikis em 21/03
3

Acho regex ser tedioso e demorado, dada a sintaxe. Como você já está usando javascript, é mais fácil fazer o seguinte sem 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
fonte
2
Funciona para mim! resposta fantástica porque é realmente muito simples! :)
Andrew Irwin
2

Se os dados estiverem em várias linhas, talvez seja necessário usar o seguinte,

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

My cow always gives 
milk

Exemplo da Regex 101

Naresh Kumar
fonte
0

O método match () pesquisa uma string por uma correspondência e retorna um 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
fonte
0

Tarefa

Extrair substring entre duas strings (excluindo essas duas strings)

Solução

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
fonte