在两个字符串之间匹配字符串

3
如果我有一个像这样的字符串:
var str = "play the Ukulele in Lebanon. play the Guitar in Lebanon.";

我希望能够获取在每个"play"和"in"子字符串之间的文本,即一个包含 "the Ukelele" 和 "the Guitar" 的数组。

目前我正在执行以下操作:

var test = str.match("play(.*)in");

但是这会返回第一个“play”和最后一个“in”之间的字符串,因此我得到的是“在黎巴嫩的尤克里里。弹奏吉他”而不是两个单独的字符串。有人知道如何全局搜索一个字符串以查找起始字符串和结束字符串之间子字符串的所有出现吗?


2
str.match("play(.*)in") ==> str.match(/play(.*?)in/g) - Tushar
4个回答

9

您可以使用正则表达式

play\s*(.*?)\s*in

  1. 使用/作为正则表达式文字语法的分隔符
  2. 使用惰性匹配组以尽可能少地匹配

Demo:

var str = "play the Ukulele in Lebanon. play the Guitar in Lebanon.";
var regex = /play\s*(.*?)\s*in/g;

var matches = [];
while (m = regex.exec(str)) {
  matches.push(m[1]);
}

document.body.innerHTML = '<pre>' + JSON.stringify(matches, 0, 4) + '</pre>';


我在你的表达式中发现了一些可能的问题。我在我的回答中引用了它。 - Jon
谢谢,这很完美 ;) - STEEL

3

你距离正确答案很近了。以下是一些可能被忽略的事项:

  1. 你需要使用非贪婪匹配,这可以通过使用 ? 操作符来实现
  2. 不要使用 String.match() 方法,因为它已被证明会完全匹配模式,并且不像你期望的那样关注捕获组。一个替代方法是使用 RegExp.exec()String.replace(),但使用 replace 需要更多的工作,所以最好使用 exec 来构建自己的数组。

var str     = "display the Ukulele in Lebanon. play the Guitar in Lebanon.";
var re      = /\bplay (.+?) in\b/g;
var matches = [];
var match;

while ( match = re.exec(str) ){
  matches[ matches.length ] = match[1];
}


document.getElementById('demo').innerHTML = JSON.stringify( matches );
<pre id="demo"></pre>


谢谢您,先生,这是一个很好的答案。另一个用户给了我/play\s*(.*?)\s*in/g的正则表达式,但是您的看起来更简单。语法看起来有点混乱,所以我还在努力理解它。 - MarksCode
我一直在忙着打字,没有注意到 @Tushar 几乎给出了相同的答案,除了对数组赋值的值。在 JavaScript 中,您可以使用 \s\ 来引用空格。但是在其他地方要小心,比如 Perl 中, 可能会被忽略。此外,\s 不仅指空白字符,还可能表示制表符或换行符。 - vol7ron
@vol7ron:我在你的表达式中发现了一些可能的问题。我在我的答案中引用了它。 - Jon
@Jon 谢谢,你是正确的,这可以使用单词边界。请记住,即使单词边界也可能存在连字符问题。最健壮的解决方案需要更多的逻辑行 - 或者负回顾(我认为ECMAScript RegEx不允许)。因此,这也需要OP更具体地说明正在评估的字符串。话虽如此,\b也是一个好东西要包括。 - vol7ron
@vol7ron:是的,\b可能会与许多特殊字符产生问题。我可能比实际需要更加关注此事,因为OP处理的字符串可能与他提供的字符串变化很小,在这种情况下,\b是不必要的。此外,他的问题可能只是关于贪婪与懒惰的区别。但我想,虽然已经提出了\b可能存在潜在问题的问题(正如你所暗示的,没有更多了解他的输入字符串的可能变化),也许以下内容会更安全:/(?:\s|^)play\s+(.+?)\s+in\s/ig - Jon

2
/\bplay\s+(.+?)\s+in\b/ig 可能更加精确并且对你更有效。之前提供的正则表达式可能存在一些问题。例如,/play\s*(.*?)\s*in/g 会在“displaying photographs in sequence”中找到匹配项。当然这不是你想要的。其中一个问题是没有指定“play”应该是一个独立的单词。它需要一个词边界在它之前,并且至少有一个空格实例在它之后(它不能是可选的)。同样,捕获组后面的空格也不应该是可选的。此外,我添加的另一个表达式/play (.+?) in/g 在“display blue ink”中缺少“play”之前和“in”之后的词边界标记,因此它将包含匹配项。这不是你想要的。至于你的表达式,它也缺少了词边界和空格标记。但是,正如另一个人提到的那样,它还需要通配符是懒惰的。否则,给定你的示例字符串,你的匹配将从第一个“play”的实例开始,并以第二个“in”的实例结束。如果发现我的提供的表达式存在问题,请给予反馈。

0
一个贪婪匹配的受害者。
.* 找到最长的匹配,
而 .*? 找到最短的匹配。
对于给定的示例,str 将是包含 3 个字符串的数组:
    the Ukelele
    the Guitar
    Lebanon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接