【问题标题】:How do you access the groups of match/matchAll like an array?如何像数组一样访问 match/matchAll 组?
【发布时间】:2021-10-30 15:11:12
【问题描述】:

这是我想做的事情:

function convertVersionToNumber(line) {
  const groups = line.matchAll(/^# ([0-9]).([0-9][0-9]).([0-9][0-9])\s*/g);

  return parseInt(groups[1] + groups[2] + groups[3]);
}

convertVersionToNumber("# 1.03.00")

这不起作用,因为groupsIterableIterator<RegExpMatchArray>,而不是数组。 Array.from 似乎也没有把它变成一组组。有没有一种简单的方法(理想情况下可以放在一行上)可以将groups 转换为数组?

IterableIterator<RegExpMatchArray> 的 API 有点不方便,我不知道如何跳过for...of 中的第一个元素。我的意思是,我确实知道如何使用这两个,它似乎要添加 4+ 行所以我想知道是否有更简洁的方法。

我正在使用打字稿,所以如果它有任何语法糖可以做到这一点,我很乐意使用它。

【问题讨论】:

  • 你能不能试着用Array.from包裹line.matchAll
  • @zecuria 在我实际问这个问题之前我试过了。我不知道它返回的是什么,但它似乎没有将它返回到数组中。
  • @zecuria 感谢上帝的打字稿。我的 IDE 告诉我它正在返回 RegExpMatchArray[]。但这不能加在一起。

标签: javascript regex typescript


【解决方案1】:

1) matchAll 将返回一个迭代器对象 Iterator [RegExp String Iterator]

result 将包含一个迭代器,当您使用扩展运算符时,它将为您提供所有匹配项。由于它只包含一个匹配项,所以它只包含一个元素。

[ '# 1.03.00', '1', '03', '00', index: 0, input: '# 1.03.00', groups: undefined ]

最后,我们使用扩展运算符来获取所有值并将其包装在一个数组中

[...result]

function convertVersionToNumber(line) {
  const result = line.matchAll(/^# ([0-9]).([0-9][0-9]).([0-9][0-9])\s*/g);
  const groups = [...result][0];
  return parseInt(groups[1] + groups[2] + groups[3]);
}

console.log(convertVersionToNumber("# 1.03.00"));

由于您使用的是正则表达式,即/^# ([0-9]).([0-9][0-9]).([0-9][0-9])\s*/

2)如果有多个匹配项,那么你可以将结果分布在一个数组中,然后使用for..of 循环匹配项

function convertVersionToNumber(line) {
  const iterator = line.matchAll(/# ([0-9]).([0-9][0-9]).([0-9][0-9])\s*/g);
  const results = [...iterator];
  for (let arr of results) {
    const [match, g1, g2, g3] = arr;
    console.log(match, g1, g2, g3);
  }
}

convertVersionToNumber("# 1.03.00 # 1.03.00");

替代解决方案:您也可以使用简单匹配获得相同的结果

function convertVersionToNumber(line) {
  const result = line.match(/\d/g);
  return +result.join("");
}

console.log(convertVersionToNumber("# 1.03.00"));

【讨论】:

  • 为什么我需要[0][...result][0]
  • 因为它是一个迭代器,所以第一个里面有多个。
  • @HR01M8055 nm,我推断这取决于字符串,就像它是 # 1.03.00 # 1.03.00(我的正则表达式中没有 ^)。
  • @DanielKaplan 我已经用正则表达式图像更新了结果。看看
  • @DanielKaplan 我再次更新了答案,如果您有多个匹配项,则包括您所期望的。
【解决方案2】:

在这种具体情况下,您不需要.matchAll。您只需要匹配特定格式的字符串并通过仅保留三个捕获的子字符串来重新格式化它。

您可以使用.replace

function convertVersionToNumber(line) {
  return parseInt(line.replace(/^# (\d)\.(\d{2})\.(\d{2})[\s\S]*/, '$1$2$3'));
}
console.log( convertVersionToNumber("# 1.03.00") );

如果你需要检查是否有匹配,你可以检查替换前的字符串是否等于新字符串。

请注意,您需要转义点以将它们匹配为文字字符。

^# (\d)\.(\d{2})\.(\d{2})[\s\S]* 模式匹配

  • ^ - 字符串开头
  • # - 空格 + #
  • (\d) - 第 1 组:一个数字
  • \. - 一个点
  • (\d{2}) - 第 2 组:两位数
  • \. - 一个点
  • (\d{2}) - 第 3 组:两位数
  • [\s\S]* - 字符串的其余部分(零个或多个字符,尽可能多)。

$1$2$3 替换模式是串联的 Group 1、2 和 3 值。

【讨论】:

  • 我更喜欢这个解决方案,但我希望你不介意我继续接受 HR01M8055,因为从技术上讲,它回答了 OP,即使你的提供了更多价值,我要去改为使用它。我不知道 replace 的第二个参数可以指代组。我想我只是假设它不能,因为它是一个字符串而不是一个正则表达式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-01
  • 2016-09-17
  • 1970-01-01
  • 2011-08-18
  • 1970-01-01
  • 2021-07-14
相关资源
最近更新 更多