【问题标题】:Regexp with global flag only matching first match具有全局标志的正则表达式仅匹配第一个匹配项
【发布时间】:2012-09-05 15:40:35
【问题描述】:

为什么会这样:

/(\[#([0-9]{8})\])/g.exec("[#12345678] [#87654321] [#56233001] [#36381069] [#23416459] [#56435355]")

返回

[“[#12345678]”、“[#12345678]”、“12345678”]

我希望它匹配所有这些数字,但它似乎太贪心了。

[#12345678] [#87654321] [#56233001] [#36381069] [#23416459] [#56435355] 12345678 87654321 56233001 36381069 23416459 56435355

【问题讨论】:

  • 它并不贪心。 exec 仅显示第一个匹配项,但返回一个数组。因此,遍历匹配数组并删除外部捕获括号。

标签: javascript regex regex-greedy


【解决方案1】:

.exec() 就是这样工作的。要获得多个结果,请循环运行。

var re = /(\[#([0-9]{8})\])/g,
    str = "[#12345678] [#87654321] [#56233001] [#36381069] [#23416459] [#56435355]",
    match;

while (match = re.exec(str)) {
    console.log(match);
}

此外,外部捕获组似乎无关紧要。您可能应该摆脱它。

/\[#([0-9]{8})\]/g,

结果:

[
    "[#12345678]",
    "12345678"
],
[
    "[#87654321]",
    "87654321"
],
[
    "[#56233001]",
    "56233001"
],
[
    "[#36381069]",
    "36381069"
],
[
    "[#23416459]",
    "23416459"
],
[
    "[#56435355]",
    "56435355"
]
【解决方案2】:

regex.exec 返回正则表达式中的组(括号中的内容)。

您要查找的函数是您在字符串match 上调用的函数。

string.match(regex) 返回所有匹配项。

"[#12345678] [#87654321] [#56233001] [#36381069] [#23416459] [#56435355]".match(/(\[#([0-9]{8})\])/g)
// yields: ["[#12345678]", "[#87654321]", "[#56233001]", "[#36381069]", "[#23416459]", "[#56435355]"]

编辑:

如果您只想要不带括号和 # 的数字,只需将正则表达式更改为 /\d{8}/g

"[#12345678] [#87654321] [#56233001] [#36381069] [#23416459] [#56435355]".match(/[0-9]{8}/g)
// yields: ["12345678", "87654321", "56233001", "36381069", "23416459", "56435355"]

【讨论】:

  • 唯一的问题是使用.match时会丢失捕获组。
  • 不清楚 OP 的最终目标是什么。在这种情况下,谁需要捕获组?你知道前面有一个[#,后面是]
  • 我想说分组数字很可能是目标。假设没有其他可能导致误报的数字集,您更新的正则表达式将起作用。从给定的示例中,我认为它可以安全使用。
【解决方案3】:

您可以使用字符串的replace 方法来收集所有匹配项:

var s = "[#12345678] [#87654321] [#56233001] [#36381069] [#23416459] [#56435355]";
var re = /\[#([0-9]{8})\]/g;
var l = [];
s.replace(re, function($0, $1) {l.push($1)});
// l == ["12345678", "87654321", "56233001", "36381069", "23416459", "56435355"]

【讨论】:

  • 当我们有match时,这里不需要使用替换
  • @Kash:如果要使用捕获组,那么您需要.replace() 来访问组值(假设使用 String 方法而不是 RegExp 方法).
  • 组值已经在二维数组中了,我们要替换什么呢?
  • @Kash: 使用.match,结果是["[#12345678]", "[#87654321]", "[#56233001]", ...] 想要的结果是["12345678", "87654321", "56233001", ...]。没有任何东西被替换,但是使用.replace() 可以让您访问子组,因此可以将其推送到结果数组中。使用.match(),您会丢失子组,因此您需要循环结果并删除不需要的字符。
  • 括号中捕获的实际值在数组中仍然可用。检查我的答案。
【解决方案4】:

试试这个:

    var re = /\[#(\d{8})\]/g;
    var sourcestring = "[#12345678] [#87654321] [#56233001] [#36381069] [#23416459] [#56435355]";
    var results = [];
    var i = 0;
    var matches;
    while (matches = re.exec(sourcestring)) {
        results[i] = matches;
        alert(results[i][1]);
        i++;
    }

【讨论】:

    【解决方案5】:

    在 ES2020 中添加了一个新功能 matchAll 女巫可以完成这项工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-01
      • 1970-01-01
      • 2017-11-17
      • 2011-06-17
      • 1970-01-01
      • 2011-04-05
      • 1970-01-01
      • 2020-12-03
      相关资源
      最近更新 更多