如何将多个数字序列捕获为重复组?

问题描述

我有一个包含多个数字序列的 URL 我想将它们全部分组捕获,假设我有以下内容

https://www.example.com//first/part/54323?key=value

https://www.example.com/first/12345/second/part/part2/5432?key=value

我尝试使用类似的东西,但它只匹配一个数字序列

(.*\/)([0-9]{4,})(\/.*|$|)

如果包含数字序列,我希望多个组代表不同的部分

  • 第一组将是“example.com/first”
  • 第二组“12345”
  • 第三组“第二/部分”
  • 第四组“5432”
  • 第 5 组“?key=value”

解决方法

最初的 .* 是贪婪的,这意味着它会尝试尽可能多地匹配。它匹配最后一个斜杠“https://www.example.com/first/12345/second/part”之前的所有内容。您可以通过将开头的 .* 替换为 .*? 来修改此行为,但这将在第一个斜杠之后停止,这也不是您想要的“https:/”,因为这些斜杠后面没有数字。>

但实际上我们需要备份并询问有关您的模式的一些问题。显然,您有一个您不感兴趣的序言,无限数量的“字符串,后跟斜杠,后跟数字字符串”的序列,然后是“没有更多斜杠数字模式之后的所有内容”。>

关键问题是 char/char/digits 组合的数量是不确定的还是像您示例中的两对一样仅限于确定的数字。要让正则表达式解析器返回无限数量的字符串-数字对,您需要打开 /g(全局)开关,以便正则表达式返回所有匹配项。这是 URL 开头和结尾部分不符合您的模式的问题。

我建议首先使用正则表达式将您的网址分成三部分,preamble,path,remaining data。然后你可以将路径字符串传递给第二个正则表达式来解析这些对 - 会简单得多。

如果你这样做,你的第一个表达可能是:

^[a-z+.-]+?:\/\/(:www\.)?([^?#]+?)(.*)$

第一部分通过可选的 www. 跳过所有内容并且没有捕获它,因为您对该部分不感兴趣。第二部分捕获任何查询或片段(分别由 ? 和 # 分隔)之前的所有内容,并将其放在第一个捕获组中。最后一部分将 URL 的其余部分捕获到第二个捕获组中。在您的示例中,?key=value

现在获取包含主机和路径的第一个捕获组,并将其传递给设置了全局标志的第二个正则表达式(因此它重复处理所有对)。第二个正则表达式将是:

(.*?)\/([0-9]{4,})\/?

对于此字符串的每个匹配项,解析的值和数字将位于捕获组 1 和 2 中。