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

IT技术 javascript regex string
2021-01-14 23:14:47

我发现了非常相似的帖子,但我不能在这里得到我的正则表达式。

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

我的牛总是产奶

会回来

“总是给予”

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

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

但是,这会返回字符串“cow always Gives”。

6个回答

前瞻(那(?=部分)不消耗任何输入。这是一个零宽度断言(边界检查和后视)。

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

cow(.*)milk

根本不需要前瞻。

@sborn - 感谢您指出这一点。我认为这个问题为解释提供了空间。我想到的是一个(香草 - 尽可能多的)正则表达式,它过滤原始消息并提供所要求的结果。这个正则表达式就是这种情况:/([^(my cow)])(.*)[^(milk)]/g请检查jsfiddle.net/almircampos/4L2wam0u/5 上的小提琴,让我们知道您的想法。
2021-03-18 23:14:47
当我对此进行测试时,提供的 Regex 表达式包括“cow”和“milk”...
2021-03-22 23:14:47
这少了一步。当你得到匹配结果时,你需要提取第一个捕获组matched[1]的匹配文本,而不是整个匹配文本matched[0]
2021-03-25 23:14:47
在 Javascript 中,您实际上需要使用([\s\S]*?)而不是(.*?).
2021-04-06 23:14:47
虽然这是一个有用的技术,但它被否决了,因为恕我直言,这不是问题的正确答案,因为它包括“奶牛”和“牛奶”,正如@TheCascadian 所说
2021-04-07 23:14:47

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

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

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

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

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 或更多空格)。

场景一:单线输入

所有 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 个匹配项,因为在找到第一个匹配项时已经消耗>>>before 您可以使用正向前瞻来检查文本是否存在,而无需实际“吞噬”它(即附加到匹配项):67

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

请参阅在线正则表达式演示生成text1text2找到的第 1 组内容。

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

性能注意事项

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

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

请参阅正则表达式演示(如果可以\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]));

我也写了一篇关于使用正则表达式在两个字符串之间提取字符串的一般文章,如果您在处理当前的类似问题时遇到问题,请随时阅读。
2021-03-29 23:14:47

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

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

一个例子:http : //jsfiddle.net/entropo/tkP74/

  • 你需要捕捉 .*
  • 您可以(但不必)使非.*贪婪
  • 真的不需要前瞻。

    > /cow(.*?)milk/i.exec('My cow always gives milk');
    ["cow always gives milk", " always gives "]
    
在这个特定的例子中,如果它是贪婪的,它会到达终点并回溯(大概)。
2021-03-20 23:14:47

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

只需在牛和/或牛奶之前添加空格以修剪“总是给出”中的空格

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

在此处输入图片说明

?<=Javascript 不支持向后查看
2021-03-13 23:14:47
@MarkCarpenterJr 如果您通过regextester.com对其进行了测试,则会得到该提示。似乎该站点的规则基于较旧的规范。现在支持后视。请参阅stackoverflow.com/questions/30118815/...该模式适用于现代浏览器,不会出错。试试这个检查器而不是regex101.com
2021-04-06 23:14:47