正则表达式以获取Javascript中两个字符串之间的字符串


166

我发现了非常相似的帖子,但是我在这里无法完全得到正则表达式。

我正在尝试编写一个正则表达式,该表达式返回一个位于其他两个字符串之间的字符串。例如:我想获取字符串“ cow”和“ milk”之间的字符串。

我的牛总是喂牛奶

会回来

“总是给”

到目前为止,这是我拼凑的表达方式:

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

但是,这将返回字符串“牛总是给”。


6
我偶然发现了这个老问题,想弄清楚为什么testRE是一个数组。test.match返回一个数组,该数组的第一个索引为总匹配项(例如,匹配cow(。*)milk的字符串),然后,如果存在第二组括号,则所有被捕获的字符串(如(。*))都将然后进入testRE [2]
Salketer 2013年

4
如果要搜索包含换行符的字符串,则此解决方案将不起作用。在这种情况下,应使用“ STRING_ONE([\\ s \\ S] *?)STRING_TWO”。stackoverflow.com/questions/22531252/...
Michael.Lumley

Answers:


183

前瞻(该(?=部分)不消耗任何输入。这是一个零宽度的断言(边界检查和回溯也是如此)。

您要在此处进行常规匹配以消耗该cow部分。要捕获之间的部分,可以使用捕获组(只需将要捕获的模式部分放在括号内):

cow(.*)milk

完全不需要前瞻。


26
当我对此进行测试时,提供的Regex表达式同时包括“牛”和“牛奶” ...
TheCascadian '18

4
这缺少一个步骤。获得匹配结果时,需要使用提取第一个捕获组matched[1]的匹配文本,而不是使用提取整个匹配文本matched[0]
罗里·奥肯

7
在Javascript中,您实际上需要使用([\s\S]*?)而不是(.*?)
钱琛

7
尽管这是一种有用的技术,但它被否决了,因为恕我直言,这不是该问题的正确答案,因为它包括“牛”和“牛奶”,如@TheCascadian所述
Almir Campos

@AlmirCampos-如果我没记错的话,没有匹配“ cow”和“ milk”的方法是不可能的(因为你想匹配这两个之间的匹配)。问题不在于RegEx本身,而在于后来的处理方式(如Rory O'Kane所述)。否则,您只能匹配周围的空间-这样会给您非常错误的回报,不是吗?
日出生于

69

正则表达式以获取JavaScript中两个字符串之间的字符串

在绝大多数情况下,最完整的解决方案是使用具有惰性点匹配模式捕获组。然而,一个点在JavaScript中的正则表达式不匹配换行符,所以,你会在100%的情况下工作是一种或/ / 构造。.[^][\s\S][\d\D][\w\W]

ECMAScript 2018和更新的兼容解决方案

在支持ECMAScript 2018的 JavaScript环境中,s修饰符允许.匹配任何字符,包括换行符,并且正则表达式引擎支持可变长度的后向。因此,您可以使用像

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

在这两种情况下,都会检查后是否cow有1/0或更多空格的当前位置cow,然后匹配并消耗尽可能少的任何0+个字符(=添加到匹配值中),然后milk检查(是否有任何此子字符串前的1/0或多个空格)。

方案1:单行输入

所有JavaScript环境都支持以下这种情况以及所有其他情况。请参阅答案底部的用法示例。

cow (.*?) milk

cow首先找到一个空格,然后将除换行符以外的所有0+个字符(尽可能少的作为*?惰性量)捕获到组1中,然后milk必须跟随一个空格(并且匹配并消耗了这些空格),也)。

方案2:多行输入

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

在这里,cow先匹配一个空格,然后匹配尽可能少的任何0+个字符并将其捕获到组1中,然后使用milk匹配。

方案3:重叠比赛

如果您有一个类似这样的字符串,>>>15 text>>>67 text2>>>并且您需要在>>>+ number+ whitespace和之间获得2个匹配项>>>,则您将无法使用它,/>>>\d+\s(.*?)>>>/g因为只能找到1个匹配项,因为查找第一个匹配项>>>之前67已经消耗了before 的事实。您可以使用正向前瞻来检查文本是否存在,而无需实际“吞噬”文本(即追加到匹配项中):

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

参见在线正则表达式演示 yield text1text2第1组内容。

另请参见如何获取字符串的所有可能重叠匹配

性能考量

.*?如果输入的时间很长,则正则表达式模式中的惰性点匹配模式()可能会减慢脚本的执行速度。在许多情况下,展开循环技术在更大程度上有所帮助。试图抓住之间的所有cowmilk来自"Their\ncow\ngives\nmore\nmilk"中,我们看到,我们只需要匹配不启动的所有行milk,因此,不是cow\n([\s\S]*?)\nmilk我们可以使用:

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

请参阅regex演示(如果可以\r\n,请使用/cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm)。使用这个小的测试字符串,性能提升可以忽略不计,但是使用非常大的文本,您会感觉到差异(特别是如果行很长且换行不是很多的话)。

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);

使用现代String#matchAll方法

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]));


51

这是一个正则表达式,它将捕获牛奶和牛奶之间的内容(没有前导/尾随空间):

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

示例:http//jsfiddle.net/entropo/tkP74/


17
  • 您需要捕获 .*
  • 您可以(但不必)使自己变得不.*贪心
  • 确实不需要前瞻。

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

在这种特定情况下,如果贪婪,它将到达末尾并回溯(大概)。

9

选择的答案对我不起作用...嗯...

只需在牛后和/或牛奶前添加空间,以修剪“始终给”的空间

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

在此处输入图片说明


您无需评论自己的答案,只需对其进行编辑。
科迪G

?<=Javascript不支持“向后看” 。
马克·卡彭特(Marc Carpenter Jr)'18年

如果您通过regextester.com测试了@MarkCarpenterJr,则将获得该提示。该网站似乎已根据较早的规范制定了规则。现在支持Lookbehind。请参阅stackoverflow.com/questions/30118815/…并且该模式在现代浏览器中也能正常运行而不会出错。请改用此检查器regex101.com
duduwe

@ CodyG.ah是的。得到它了。
duduwe

8

使用下面的Martinho Fernandes的解决方案,我可以获得所需的东西。代码是:

var test = "My cow always gives milk";

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

您会注意到,我警告testRE变量为数组。这是因为出于某种原因,testRE作为数组返回。来自的输出:

My cow always gives milk

更改为:

always gives

1
谢谢,我为此添加了一个小提琴(jsfiddle.net/MoscaPt/g5Lngjx8/2)。/约翰
莫斯卡铂


3

考虑到语法,我发现正则表达式既繁琐又耗时。由于您已经在使用javascript,因此无需使用正则表达式即可更轻松地执行以下操作:

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"

2
为我工作!很棒的答案,因为它真的很简单!:)
Andrew Irwin


0

match()方法在字符串中搜索匹配项,并返回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

任务

提取两个字符串之间的子字符串(不包括这两个字符串)

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]);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.