正则表达式:忽略捕获组的顺序,仅捕获最后一次出现。

4
假设我们有以下字符串:
1|order=asc|type=1

我们需要创建一个正则表达式来解析参数,假设字符串始终以数字开头,并且(可选)具有任意顺序的参数(order,asc)。另外,它可能具有3个或更多参数,但出于简单起见,让我们保留2个参数。

例如,这些是正则表达式将理解的字符串:

1
1|order=asc|type=1
1|type=1|order=asc

我有以下表达式可以完成此任务:

(?<id>^\w+)((?:\|type=(?<type>\w+))|(?:\|order=(?<order>\w+))){0,2}

这是我正则表达式的演示链接

但问题在于它允许重复。

如果我们有以下字符串,它将根本不匹配order参数:

1|type=1|type=2|order=asc

理想情况下,我们应该从上面的正则表达式中获得以下几个组:
  • id:1
  • type:2(因为它应该捕获最后出现的实例)
  • order:asc

1
也许类似于 ^(?<id>\w+)(?:\|(?:type=(?<type>\w+)|order=(?<order>\w+)))+$ 的正则表达式可以实现这个功能?请参考 https://regex101.com/r/uZJfkp/1 - Wiktor Stribiżew
要从第一个输入中捕获<id>,需要使用*而不是+。@WiktorStribiżew。不错的解决方案。发布一下吗? - JvdV
是的,在最后一组中应该使用 * - Wiktor Stribiżew
1
如果您需要支持未知参数,可以将\w+=\w*模式作为替代方案添加,.*匹配太多。请参见^(?<id>\w+)(?:\|(?:type=(?<type>\w+)|order=(?<order>\w+)|num=(?<num>\d+)|status=(?<status>\w+)|\w+=\w*))*\|?$演示)。 - Wiktor Stribiżew
1个回答

4

您可以使用

^(?<id>\w+)(?:\|(?:type=(?<type>\w+)|order=(?<order>\w+)))*$

查看正则表达式演示

细节:

  • ^ - 字符串开头
  • (?<id>\w+) - "id" 组:一个或多个单词字符
  • (?:\|(?:type=(?<type>\w+)|order=(?<order>\w+)))* - 零或多个重复出现的
    • \| - 一个 | 字符
    • (?:type=(?<type>\w+)|order=(?<order>\w+)) - 二选一:
      • type=(?<type>\w+)| - type= 文本,然后是捕获一个或多个单词字符的 "type" 组,接着是一个或运算符
      • order= - 文本 order=,然后是
      • (?<order>\w+) - "order" 组:一个或多个单词字符
  • $ - 字符串结尾。

(?:...)*重复组内的捕获组将在每次捕获字符串时保持重写组值,因此将保留最后出现的组。

您可以通过在第二个非捕获组中添加更多组来增强此正则表达式。例如,添加 numstatus 就很容易:

^(?<id>\w+)(?:\|(?:type=(?<type>\w+)|order=(?<order>\w+)|num=(?<num>\d+)|status=(?<status>\w+)))*$

参见此正则表达式演示


1
@Thefourthbird 我们只需要记住,在JavaScript和ECMAScript中,这个技巧不起作用,因为非参与组在每次捕获时都会被重新初始化为空字符串(只有最后一个捕获的组实际上被填充了值,其余的将为空)。 - Wiktor Stribiżew
好好知道,我之前并不知道。还是个好答案。 - The fourth bird

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