2 回答
TA贡献1847条经验 获得超11个赞
每个参数应该只匹配一次。
是主要问题。
对于您的示例,我提出了以下正则表达式:
/abcd\s*\((?!(?:'[^']*'|[^')])*(?<=[\s(,])(name|count|id)(?=[\s=])(?:'[^']*'|[^')])*(?<=[\s,])\1(?=[\s=]))(?:(?<=[(,])\s*(?:name\s*=\s*'(?<name>[^']*?)'|count\s*=\s*'(?<count>[^']*?)'|id\s*=\s*'(?<id>[^']*?)')\s*[,)]){3}(?<=\))
它很长,所以让我们分解一下。
/<function name>\s*\(...(?<=\))
匹配函数名称function name
、开头(
(+ 断言正则表达式以结尾结束)
)、可选空格(我不会在正则表达式的其余部分讨论)和/
名称前的 a。请注意,java 不需要转义/
.
(?!...)
这是检查没有参数被多次使用的部分。将...
被一个子正则表达式替换,如果相同的值被使用两次,该子正则表达式将匹配。子正则表达式是完整正则表达式的分解形式,用于模拟匹配的名称-值对。
(?:'[^']*'|[^')])*
匹配(尽可能多)既不是也不是'
结束符的任何字符,或者)
匹配一个由 分隔且不包含的值。这将有效地读取空格、逗号、等号和 argnames 以及完整的值。'
'
(?<=[\s(,])(<argname1>|<argname2>|...)(?=[\s=])
匹配任何参数名称argname<n>
。还要检查它是一个完整的名称,而不仅仅是一个子字符串。(
如果名称前有空格、逗号或空缺,则这是一个完整的名称。完整名称后是空格或=
. 匹配的 argname 存储在捕获组 1 中。请注意,此子正则表达式(在 中)以匹配任何(?!...)
名称的方式编写。因此它将尝试匹配所有 argnames 并仅在没有(no = not any)argname 被使用两次时才接受。
(?:'[^']*'|[^')])*
同上。匹配每个字符或完整值。
(?<=[\s,])\1(?=[\s=])
将第一个捕获组(任何 argname)的内容重新匹配为完整名称(名称前的空格或逗号,=
名称后的空格或逗号)。这是重要的部分。 这是第二次使用参数名称的测试。
(?:(?<=[(,])\s*(?:...)\s*[,)]){<num arguments>}
匹配num arguments
许多参数。每个参数必须以开头(
(第一个)或逗号(除第一个以外的所有内容)开头。此外,每个参数必须以逗号或结束符结尾)
。
包含...
参数规范和捕获组的形式
<argname1>\s*=\s*'(?<argname1>[^']*)'|<argname2>\s*=\s*'(?<argname2>[^']*)'|...
其中 for 的值agname<n>
存储在具有相同名称的捕获组中。Matcher
您可以使用 argname 作为组名从 java 中获取该值。举个例子matcher.group("count")
。
TA贡献1836条经验 获得超5个赞
如果要将选项与它们之间的逗号匹配,可以在 id 的值之后更改()
for ,并为结束参数添加一个额外的子句,
此正则表达式(与您的略有不同)将匹配括号之间的任意数量的参数,以逗号和空格分隔
\/abcd\((id='[^']*', |name='[^']*', |count='[^']*', )*(id='[^']*'|name='[^']*'|count='[^']*')\)
您可以在这里试用regexr.com/4iqlu
编辑:将 .* 替换为 [^']*,因为我们要确保正则表达式不会在 '' 之外捕获
添加回答
举报