【问题标题】:Repeat capturing group of comma seperated key value pairs重复捕获逗号分隔的键值对组
【发布时间】:2021-04-30 07:21:49
【问题描述】:

我目前正在尝试从 @Apple(kind="Bax", priority=33) 等模式中提取以下内容

  • 苹果
  • [种类,Bax],[优先级,33]

我目前使用的是@([^(]*)\(([^\)]*)\)。然后我有Applekind="Bax", priority=33。在此之后,我在 , 上拆分第 2 组,然后在 = 上拆分,最后在开始或结束时删除 "

现在这将遍历第二段很多。首先是正则表达式捕获,然后找到所有,,然后每次遍历再次找到=等。

既然我这样做了数百万次,有没有办法通过正则表达式遍历来捕获它?我想避免所有的分裂。

【问题讨论】:

    标签: regex optimization pcre


    【解决方案1】:

    假设您希望 key=value 对的计数为任意长度,那么如何:

    (?:@|\(|,\s*|="?)(\w+)(?=\(|=|"|,|\))
    

    Demo

    所有捕获都在第 1 组中。

    • (?:@|\(|,\s*|="?) 匹配 @(, 之一加上大于 0 的空格, 或= 加上可选的"
    • (\w+) 匹配所需的单词并在 Group1 中捕获。
    • (?=\(|=|"|,|\)) 是匹配( 之一的正向前瞻断言, =",)

    [编辑]

    如果双引号括起来的元素可能包含逗号,那么用单个正则表达式解析它并不容易。 如果可能的话, 它将更难维护。我会将操作分为两个步骤。 假设我们有一个字符串:

    @Apple(val="a,b", kind="Bax", priority=33,foo=bar, name="John Doe", lorem=ipsum)
    

    然后使用第一个正则表达式:

    ^@([^(]+)\(([^)]+)\)
    

    Apple 在第 1 组中被捕获,括号中的子字符串是 在第 2 组中捕获。

    然后将下一个正则表达式应用于第 2 组:

    (?<=")[^"=]+(?=")|[^,=" ]+
    

    现在我们可以获取列表了:

    ['val', 'a,b', 'kind', 'Bax', 'priority', '33', 'foo', 'bar', 'name', 'John Doe', 'lorem', 'ipsum']
    

    Demo of the 2nd regex

    【讨论】:

    • 非常好,我想“...”不可能也包含“,”?喜欢@Test(val="a,b")?
    • 感谢您的回复。是的,我想支持“...”包含逗号和单个正则表达式的情况并不容易。我已经用 2 阶段版本更新了我的答案,但我不确定它是否符合您的要求。 BR。
    【解决方案2】:

    如何创建5个不同的捕获组并相应地使用它们,你不需要使用split。请尝试以下正则表达式。

    ^@([^(]*)\(([^=]*)="(.*?)",\s+([^=]*)=([^)]*)\)
    

    Online demo for above regex

    说明:为上述添加详细说明。

    ^@        ##Matching starting @ here in value.
    ([^(]*)   ##Creating 1st capturing group which has everything till ( here.
    \(        ##Matching literal ( here.
    ([^=]*)   ##Creating 2nd capturing group which has everything till - here.
    ="        ##Matching =" here.
    (.*?)     ##Creating 3rd capturing group here, which is a lazy match till next match.
    ",\s+     ##Matching ", followed by spaces 1 or more occurrences.
    ([^=]*)   ##Creating 4th capturing group which has everything till = here.
    =         ##Matching = here.
    ([^)]*)\) ##Creating 5th capturing group which has everything till ) here, then matching literal ) here.
    

    【讨论】:

    • 一旦 OP 确认这工作正常,然后会添加详细的解释。
    • 很好的解决方案@RavinderSingh13,我真的很喜欢。一个问题,为什么(.*?) 中的? 不将* 匹配零到无限,从而使? 变得多余?
    • @NilsKähler,谢谢。 ? 它实际上表示惰性匹配,其中 .* 将是贪婪的。
    • 这不适用于可变长度,对吧?喜欢 10 个属性而不是两个
    • @Regyn,是的,它是根据显示的样本给出的。您能否展示您所说的行示例,以便更好地理解您的问题,谢谢。
    【解决方案3】:

    另一种选择可能是使用\G 锚来迭代匹配括号之间的部分,并匹配可变数量的参数。

    @后面的值在第1组,括号之间的键和值在第2组和第3组

    (?:@(\w+)\((?=[^()]*\))|\G(?!^))([^\s=]+)=(?|"([^"*"]*)"|([^\s,]+))(?:,\h*)?
    

    模式匹配:

    • (?:非捕获组
      • @(\w+) 匹配 @ 并在 group 1 中捕获 1+ 个单词字符
      • \((?=[^()]*\)) 匹配 ( 并在右侧声明关闭 )
      • |或者
      • \G(?!^) 在上一个匹配的末尾断言位置,而不是在开头(锚匹配在两个位置,也可以在字符串的开头)
    • )关闭群
    • ([^\s=]+)= 捕获 group 2,匹配除 = 或空白字符之外的任何字符,然后匹配 =
    • (?|分支重置组
      • "([^"*"]*)"|([^\s,]+) 捕获第 3 组,捕获双引号之间的内容或 1+ 个不带逗号的非空白字符
    • )(?:,\h*)? 关闭分支重置组并可选择匹配逗号和空格

    Regex demo

    【讨论】:

      【解决方案4】:

      @(\w+)\((\s*\w+="?\w+"?,?)*\)

      此正则表达式假定参数数量可变。然而,正则表达式的一个限制是你应该有一个恒定数量的捕获组:所以你只会捕获最后一个参数。

      下面的这个正则表达式使用有限数量的参数 (2) 和有限数量的捕获组 (3)

      @(\w+)\((\s*\w+="?\w+"?,?)(\s*\w+="?\w+"?,?)\) (注意:为了演示,我只是将参数捕获加倍)

      【讨论】:

        猜你喜欢
        • 2018-01-14
        • 1970-01-01
        • 1970-01-01
        • 2011-01-18
        • 1970-01-01
        • 2011-07-26
        • 2013-07-05
        • 2017-07-04
        • 1970-01-01
        相关资源
        最近更新 更多