java - 多次匹配正则表达式中的自定义模式
问题描述
我正在尝试解析一个查询,我需要修改该查询以将特定属性及其值替换为另一个属性和不同的值。我正在努力编写一个匹配我需要的指定属性及其值的正则表达式。
这里有一些例子来说明我的观点。test:property
是我们需要匹配的属性名称。
- 具有单个值的属性:
test:property:schema:Person
- 具有多个值的属性(可以有多少个值没有限制 - 此示例使用 3):
test:property:(schema:Person OR schema:Organization OR schema:Place)
- 括号中具有单个值的属性:
test:property:(schema:Person)
- 查询字符串中具有另一个属性的属性(即字符串的其他部分我不感兴趣):
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+
,即一个或多个单词字符,后跟一个冒号,然后是一个或多个单词字符。
如果我们用名称定义字符串的已知部分,我想我可以表达我想要匹配的内容。
schema:Person
-<TypeName>
- 请注意,schema
在这种情况下,第一部分不是固定的,可以是不同的test:property
-<MatchProperty>
<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+))*
解决方案
如果您想要纯正则表达式,这不是一个完整的解决方案,因为正则表达式和 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
推荐阅读
- postgresql - 在 Centos 7 上安装 Postgres10.1
- python - How to identify a change in a websites’ structure programmatically
- python - 从 pandas Dataframe 缓慢地将数据加载到 MongoDB
- nginx - nginx 正在尝试将我的后端作为静态站点提供服务
- php - json解码值类型显示为数组而不是对象
- javascript - 在猫鼬中查询ID后的第一个项目数?
- javascript - how to find exact number from url parameters inside td element
- android - android动画没有延迟
- javascript - 如何修复“TypeError:无法在'CanvasRenderingContext2D'上执行'drawImage'”?
- julia - Julia 作为非 CS 领域专家的工作语言?