【问题标题】:regex `match` returns different results based on order of lookup list正则表达式 `match` 根据查找列表的顺序返回不同的结果
【发布时间】:2020-01-03 04:34:07
【问题描述】:

我对 Javascript 的 .match 正则表达式函数感到困惑。

给定字符串:

var a = "today, I will ski with skis";

我想匹配“today”、“ski”和“skis”

a.match(/hello|today|skis|trip|ski/g);

输出:["today", "ski", "skis"]

输出符合我的预期。

但是,如果我在查找中将“ski”放在“skis”之前,对于“ski”和“skis”匹配,它会在“ski”处停止:

a.match(/hello|today|ski|trip|skis/g);

输出:["today", "ski", "ski"]

为什么它不会同时返回“ski”和“skis”,我该如何解决?


编辑:澄清一下,我正在寻找一种动态解决方案,以便在已经识别出第一组字符后继续搜索列表。我的目标是动态填充搜索词列表,我无法确定将 ? 应用于哪些字符。

即,对skis? 使用? 运算符不是动态的,因为我必须为每个可能的字符手动添加它。如果“skittles”或“ski mountain”出现在“ski”之后,这些都将被match 忽略。 ski(.*) 越来越近,但它在其边界 | 组之后返回所有内容。

【问题讨论】:

  • 如果你问为什么它不返回输入中最后一个“skis”的“ski”和“skis”,那是因为它们是重叠匹配
  • 有很多字符串是其他单词的前缀或子字符串。 var a = "today, I will ski with skittles"; ---> a.match(/hello|today|ski|trip|skittles/g); 返回["today", "ski", "ski"]。函数真的是这样工作的吗?
  • 是的正则表达式是贪婪的,一旦找到匹配项,它将继续其余的而不评估您的(...|...|...)中的其他选项
  • 感谢@Emma,这很清楚。当.match 在第一个匹配时停止时,使用? 运算符动态创建搜索词列表有点棘手(特别是在单词的情况下,例如“skittles”,在它包含之前有搜索词,例如“滑雪”)。

标签: javascript regex match


【解决方案1】:

如果您正在动态创建搜索词列表,您可以利用在第一个匹配时停止交替的事实(请参阅manual):

"x|y匹配“x”或“y”(如果没有匹配“x”)

并以相反的顺序对您的搜索词列表进行排序(例如,skisski 之前),然后加入它们以进行交替搜索:

var a = "today, I will learn to heliski with skis at the big mountain";
var search = ['hello', 'today', 'ski', 'trip', 'skis', 'big mountain'];

var regex = new RegExp('\\b' + search.sort().reverse().join('\\b|\\b') + '\\b', 'g');
console.log(a.match(regex));

【讨论】:

  • 这是一个非常聪明的解决方案! sort 然后是reverse 是否总是会导致将有问题的子字符串放在另一个字符串之后的排序?
  • 就是这个。 ?
  • sort 将始终将子字符串排在完整字符串之前,即skiskittlesskis 之前,因此使用.reverse() 可确保较长的字符串排在第一位。
  • @Growler 我改进了正则表达式,以便它检查单词边界,这样ski 就不会匹配heliski。还在搜索词中添加了两个词的短语。
【解决方案2】:

我想匹配“today”、“ski”和“skis”

你可以使用这个模式:/today|skis?/g

在这种情况下,s? 表示:s 字符是可选的,可以匹配零次或一次。

var a = "today, I will ski with skis";
var b = "today, I will ski with ski skis";
var c = "I learned to ski at the ski mountain";

var pattern = /today|skis?/g;

console.log(a.match(pattern));
console.log(b.match(pattern));
console.log(c.match(pattern));

更新:

如果你想匹配一些以ski 开头的单词,你可以使用这个正则表达式:/ski\w*/g

var a = "I learned to ski at the ski mountain";
var b = "This is a word: skittles...";

var pattern = /ski\w*/g;

console.log(a.match(pattern));
console.log(b.match(pattern));

【讨论】:

  • .match 在第一个匹配时停止时,使用? 运算符动态创建搜索词列表有点棘手(尤其是在诸如“skittles”之类的单词的情况下在包含之前搜索字词,例如“ski”)。
  • 这适用于单个字符,但不是动态解决方案。滑雪后的几个字符(如“skittles”)或两个词(如“滑雪山”)呢? var a = "I learned to ski at the ski mountain"; 我尝试 (.*) 匹配“滑雪”之后的任何字符:a.match(/(learned|ski(.*)|at)/g); 但这导致 ["learned", "ski at the ski mountain"]
  • @Growler 我已经用skittles 之类的词更新了我的答案。但我不明白ski mountain 有什么问题?
猜你喜欢
  • 2017-11-22
  • 1970-01-01
  • 2015-06-02
  • 2017-11-08
  • 2011-06-03
  • 2023-04-02
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多