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

phi*_*hil 141 javascript regex string

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

我正在尝试编写一个正则表达式,它返回一个在两个其他字符串之间的字符串.例如:我想得到字符串"cow"和"milk"之间的字符串

我的奶牛总是给奶

会回来的

"总是给"

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

(?=cow).*(?=milk)
Run Code Online (Sandbox Code Playgroud)

但是这会返回字符串"cow always give"

R. *_*des 159

前瞻(该(?=部分)不消耗任何输入.它是一个零宽度断言(边界检查和外观).

你想在这里定期匹配,消耗cow部分.要捕获其间的部分,可以使用捕获组(只需将要捕获的模式部分放在括号内):

cow(.*)milk
Run Code Online (Sandbox Code Playgroud)

根本不需要前瞻.

  • 当我测试这个时,提供的Regex表达式包括"cow"和"milk"...... (19认同)
  • 在Javascript中,实际上需要使用`([[\ s \ S] *?)`而不是`(。*?)`。 (5认同)
  • 尽管这是一个有用的技术,但它被否决了,因为恕我直言,这不是该问题的正确答案,因为它包含“牛”和“牛奶”,如@TheCascadian所述 (3认同)
  • @sborn - 感谢您指出这一点。我认为这个问题有解释的空间。我想到的是一个(普通 - 尽可能多)正则表达式,它可以过滤原始消息并提供所要求的结果。这将是这个正则表达式的情况: `/([^(my milk)])(.*)[^(milk)]/g` 请检查 https://jsfiddle.net/almircampos/4L2wam0u 上的小提琴/5/ 让我们知道您的想法。 (3认同)
  • 这是一个缺失的步骤.当你得到匹配的结果时,你需要用`匹配[1]`提取第一个捕获组的匹配文本,而不是匹配[匹配[0]`的整个匹配文本. (2认同)
  • 以防万一其他人读到这篇文章,这返回“牛总是给出牛奶”而不是“总是给出”。现在阅读“sborn”的评论。 (2认同)

Wik*_*żew 60

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

在绝大多数情况下最完整的解决方案是使用具有惰性点匹配模式捕获组.但是,JS正则表达式中的一个点与换行符不匹配,因此,在100%的情况下可以使用的是a 或//constructs..[^][\s\S][\d\D][\w\W]

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

在支持ECMAScript 2018的 JS环境中,s修饰符允许.匹配包括换行符的任何char,并且正则表达式引擎支持可变长度的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
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,cow使用任何1/0或更多的空格检查当前位置cow,然后匹配并消耗尽可能少的任何0+字符(=添加到匹配值),然后milk检查(与任何在此子字符串之前的1/0或更多空格).

场景1:单线输入

所有JS环境都支持以下所有场景.请参阅答案底部的使用示例.

cow (.*?) milk
Run Code Online (Sandbox Code Playgroud)

cow首先找到一个空格,然后是一个空格,然后除了换行符之外的任何0+字符,尽可能少的*?是一个懒惰的量词,被捕获到第1组,然后milk必须跟随一个空格(这些也是匹配和消耗的) ).

场景2:多行输入

cow ([\s\S]*?) milk
Run Code Online (Sandbox Code Playgroud)

在这里,cow首先匹配一个空格,然后将尽可能少的0个字符匹配并捕获到组1中,然后milk匹配一个空格.

场景3:重叠匹配

如果你有这样一个字符串>>>15 text>>>67 text2>>>,你需要得到2场比赛在两者之间>>>+ number+ whitespace>>>,你不能使用/>>>\d+\s(.*?)>>>/g,由于事实,因为这只会找到1场比赛>>>之前67已经消耗在发现第一个匹配.您可以使用正向前瞻来检查文本存在而不实际"吞噬"它(即附加到匹配):

/>>>\d+\s(.*?)(?=>>>)/g
Run Code Online (Sandbox Code Playgroud)

查看在线正则表达式演示产生text1text2找到的第1组内容.

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

性能考虑因素

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

/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm
Run Code Online (Sandbox Code Playgroud)

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


ent*_*opo 50

这是一个正则表达式,它将抓住牛和牛奶之间的东西(没有前导/尾随空间):

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

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


Mat*_*all 16

  • 你需要抓住 .*
  • 你可以(但不是必须)做出.*非常规的
  • 真的没有必要进行前瞻.

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


tho*_*mas 14

您可以使用该方法match()提取两个字符串之间的子字符串。尝试以下代码:

var str = "My cow always gives milk";
var subStr = str.match("cow(.*)milk");
console.log(subStr[1]);
Run Code Online (Sandbox Code Playgroud)

输出:

总是给予

请参阅此处的完整示例:如何查找两个字符串之间的子字符串


phi*_*hil 8

我能够在下面使用Martinho Fernandes的解决方案得到我需要的东西.代码是:

var test = "My cow always gives milk";

var testRE = test.match("cow(.*)milk");
alert(testRE[1]);
Run Code Online (Sandbox Code Playgroud)

您会注意到我正在将testRE变量警告为数组.这是因为testRE由于某种原因返回为数组.输出来自:

My cow always gives milk
Run Code Online (Sandbox Code Playgroud)

变成:

always gives
Run Code Online (Sandbox Code Playgroud)


dud*_*uwe 8

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

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

/(?<=cow ).*(?= milk)/
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

  • JavaScript 不支持 Look Behind `?&lt;=`。 (2认同)
  • @MarkCarpenterJr 如果您通过 https://www.regextester.com 测试过它,您会得到该提示。该网站的规则似乎是基于旧规范的。现在支持 Lookbehind。请参阅 /sf/ask/2108317081/ 并且该模式适用于现代浏览器,不会出现错误。试试这个检查器 https://regex101.com/ (2认同)

小智 8

鉴于语法,我发现正则表达式既乏味又耗时。由于您已经在使用 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"
Run Code Online (Sandbox Code Playgroud)

  • 它错过了两个边缘情况。1.如果主字符串中缺少start,则会抛出异常。2. 如果主字符串中缺少 end,那么它仍然会返回结果,这将是错误的匹配。 (4认同)
  • 对我有用!很棒的答案,因为它真的很简单!:) (2认同)

小智 5

只需使用以下正则表达式:

(?<=My cow\s).*?(?=\smilk)
Run Code Online (Sandbox Code Playgroud)