首页 > 解决方案 > 多次匹配正则表达式中的自定义模式

问题描述

我正在尝试解析一个查询,我需要修改该查询以将特定属性及其值替换为另一个属性和不同的值。我正在努力编写一个匹配我需要的指定属性及其值的正则表达式。

这里有一些例子来说明我的观点。test:property是我们需要匹配的属性名称。

  1. 具有单个值的属性:test:property:schema:Person
  2. 具有多个值的属性(可以有多少个值没有限制 - 此示例使用 3):test:property:(schema:Person OR schema:Organization OR schema:Place)
  3. 括号中具有单个值的属性:test:property:(schema:Person)
  4. 查询字符串中具有另一个属性的属性(即字符串的其他部分我不感兴趣):test:property:schema:Person test:otherProperty:anotherValue

另请注意,其他组合是可能的,例如其他属性位于我需要捕获的属性之前,我的属性具有多个值,而查询中存在另一个属性。

我想将整个test:property部分与该匹配中捕获的每个值进行匹配。鉴于上面的例子,这些是我正在寻找的结果:

# 匹配 团体
1 test:property:schema:Person schema:Person
2 test:property:(schema:Person OR schema:Organization OR schema:Place) schema:Person
schema:Organization
schema:Person
3 test:property:(schema:Person) schema:Person
4 test:property:schema:Person schema:Person

注意:#1 和#4 产生相同的输出。我想说明应该忽略字符串的其余部分(我只需要更改test:property键和值)。

的模式schema:Person定义为\w+\:\w+,即一个或多个单词字符,后跟一个冒号,然后是一个或多个单词字符。

如果我们用名称定义字符串的已知部分,我想我可以表达我想要匹配的内容。

<MatchProperty>: // property name (which is known and the same - in the examples this is `test:property`) followed by a colon
  ( // optional open bracket
    <TypeName>
    (OR <TypeName>)* // optional additional TypeNames separated by an OR
  ) // optional close bracket

我发现的每个示例在重复部分都有简单的字母数字字符,但我的重复模式包含冒号,这似乎让我感到困惑。我得到的最接近的是:

(test\:property:(?:\(([\w+\:\w+]+ [OR [\w+\:\w+]+)\))|[\w+\:\w+]+)

当没有其他属性时,它可以正常工作(尽管例如#2 的匹配包含整个属性和值作为第一组结果,第二组具有属性值)但是当包含其他属性时会变得疯狂。

此外,通过https://regex101.com/将该正则表达式放入我知道这是不正确的,因为方括号中的反斜杠字符完全匹配。我开始尝试捕获和非捕获组,但在放弃之前就做到了!

(?:(\w+\:\w+))(?:(\sOR\s))*(?:(\w+\:\w+))*

标签: javaregexjava-11

解决方案


如果您想要纯正则表达式,这不是一个完整的解决方案,因为正则表达式和 Java 正则表达式有一些限制,但我想出的正则表达式似乎有效。

如果您希望匹配整个序列,则以下正则表达式将起作用。

test:property:(?:\((\w+:\w+)(?:\sOR\s(\w+:\w+))*\)|(\w+:\w+))

不幸的是,重复的捕获组只会捕获最后一个匹配项,因此在具有多个值的查询(如示例 2)中,组 1 和 2 将是第一个和最后一个值(模式:Person 和模式:Place)。在没有括号的查询中,该值将在第 3 组中。

如果您知道值的最大数量,则可以生成一个包含足够组的大量正则表达式,但这可能并不理想,具体取决于您的应用程序。

另一个在任意长度的组中查找值的正则表达式使用正则表达式的正向向后查找来匹配有效值。然后,您可以生成匹配数组

(?<=test:property:(?:(?:\((?:\w+:\w+\sOR\s)+)|\(?))\w+:\w+

这种方法的问题在于, Java 后视看起来有一些限制,特别是不允许未绑定或复杂的量词。我不是 Java 人,所以我没有自己尝试过,但似乎这也行不通。如果其他人有其他解决方案,请发布另一个答案!

考虑到这一点,我可能会建议使用组合正则表达式 + 字符串解析方法。您可以使用正则表达式解析出一个或多个值(由 OR 分隔),然后拆分字符串以获得最终值。

要匹配括号内的整个部分或没有括号的单个值,您可以使用此正则表达式:

test:property:(?:\((\w+:\w+(?:\sOR\s\w+:\w+)*)\)|(\w+:\w+))

它仍然分为两组,一组匹配带括号的值,另一组匹配不带括号的值(以避免匹配不成对的括号),但它应该是可用的。

如果您想玩弄这些正则表达式或了解更多信息,这里有一个正则表达式:https ://regexr.com/65kma


推荐阅读