我对RegEx有一点了解,但此刻,它远远超出了我的能力.
我需要帮助才能在最后一个没有匹配括号的开括号之后立即找到文本/表达式.
这是开发中的开源软件(Object Pascal)的CallTip.
下面是一些例子:
------------------------------------
Text I need
------------------------------------
aaa(xxx xxx
aaa(xxx, xxx
aaa(xxx, yyy xxx
aaa(y=bbb(xxx) y=bbb(xxx)
aaa(y <- bbb(xxx) y <- bbb(xxx)
aaa(bbb(ccc(xxx xxx
aaa(bbb(x), ccc(xxx xxx
aaa(bbb(x), ccc(x) bbb(x)
aaa(bbb(x), ccc(x), bbb(x)
aaa(?, bbb(?? ??
aaa(bbb(x), ccc(x)) ''
aaa(x) ''
aaa(bbb( ''
------------------------------------
For all text above the RegEx proposed by @Bohemian
(?<=\()(?=([^()]*\([^()]*\))*[^()]*$).*?(?=[ ,]|$)(?! <-)(?<! <-)
matches all cases.
For the below (I found these cases when implementing the RegEx in the software) not
------------------------------------
New text I need
------------------------------------
aaa(bbb(x, y) bbb(x, y)
aaa(bbb(x, y, z) bbb(x, y, z)
------------------------------------
Run Code Online (Sandbox Code Playgroud)
是否可以为这些情况编写RegEx(PCRE)?
在之前的帖子中(RegEx:紧接在最后一个打开的括号之前的单词)Alan Moore(非常感谢新的)帮助我在下面的RegEx的最后一个左括号之前找到文本:
\w+(?=\((?:[^()]*\([^()]*\))*[^()]*$)
Run Code Online (Sandbox Code Playgroud)
但是,我无法进行适当的调整以便立即匹配.
有人可以帮忙吗?
这类似于这个问题.而且由于您使用PCRE,使用递归语法,实际上有一个解决方案.
/
(?(DEFINE) # define a named capture for later convenience
(?P<parenthesized> # define the group "parenthesized" which matches a
# substring which contains correctly nested
# parentheses (it does not have to be enclosed in
# parentheses though)
[^()]* # match arbitrarily many non-parenthesis characters
(?: # start non capturing group
[(] # match a literal opening (
(?P>parenthesized) # recursively call this "parenthesized" subpattern
# i.e. make sure that the contents of these literal ()
# are also correctly parenthesized
[)] # match a literal closing )
[^()]* # match more non-parenthesis characters
)* # repeat
) # end of "parenthesized" pattern
) # end of DEFINE sequence
# Now the actual pattern begins
(?<=[(]) # ensure that there is a literal ( left of the start
# of the match
(?P>parenthesized)? # match correctly parenthesized substring
$ # ensure that we've reached the end of the input
/x # activate free-spacing mode
Run Code Online (Sandbox Code Playgroud)
这种模式的要点显然是parenthesized子模式.我应该详细说明一点.它的结构是这样的:
(normal* (?:special normal*)*)
Run Code Online (Sandbox Code Playgroud)
哪里normal是[^()]和special是[(](?P>parenthesized)[)].这种技术称为"展开循环".它用于匹配任何具有结构的东西
nnnsnnsnnnnsnnsnn
Run Code Online (Sandbox Code Playgroud)
在哪里n匹配normal并s匹配special.
在这种特殊情况下,事情有点复杂,因为我们也在使用递归.(?P>parenthesized)递归地使用parenthesized模式(它是它的一部分).您可以查看(?P>...)语法有点像反向引用 - 除了引擎不会尝试匹配组...匹配的内容,而是再次应用它的子模式.
另请注意,我的模式不会为正确的括号模式提供空字符串,但会失败.你可以通过省略外观来解决这个问题.实际上并不需要后视,因为引擎将始终返回最左边的匹配.
编辑:根据你的两个例子判断,你实际上并不想要在最后一个不匹配的括号之后的所有内容,而只是在第一个逗号之前的所有内容.您可以使用我的结果并拆分,或尝试Bohemian的答案.
进一步阅读:
(?(DEFINE)...)实际上是滥用另一个称为条件模式的功能.该PCRE手册页解释它是如何工作的-只是搜索页"只有参考定义的子模式的使用".编辑:我注意到你在问题中提到你正在使用Object Pascal.在这种情况下,您可能实际上并未使用PCRE,这意味着不支持递归.在这种情况下,问题可能没有完整的正则表达式解决方案.如果我们施加一个限制,例如"在最后一个不匹配的括号之后只能有一个嵌套级别"(如在所有示例中那样),那么我们就可以提出一个解决方案.同样,我将使用"unrolling-the-loop"来匹配表单的子字符串xxx(xxx)xxx(xxx)xxx.
(?<=[(]) # make sure we start after an opening (
(?= # lookahead checks that the parenthesis is not matched
[^()]*([(][^()]*[)][^()]*)*
# this matches an arbitrarily long chain of parenthesized
# substring, but allows only one nesting level
$ # make sure we can reach the end of the string like this
) # end of lookahead
[^(),]*([(][^()]*[)][^(),]*)*
# now actually match the desired part. this is the same
# as the lookahead, except we do not allow for commas
# outside of parentheses now, so that you only get the
# first comma-separated part
Run Code Online (Sandbox Code Playgroud)
如果您添加了一个输入示例,例如aaa(xxx(yyy())您想要匹配的地方,xxx(yyy())那么此方法将无法与之匹配.实际上,没有使用递归的正则表达式可以处理任意嵌套级别.
由于你的正则表达式不支持递归,所以你最好不使用正则表达式.即使我的最后一个正则表达式匹配你当前的所有输入示例,它真的很复杂,也许不值得麻烦.相反如何:按字符逐行处理字符串并保持一堆括号位置.然后,下面的伪代码为您提供最后一次不匹配后的所有内容(:
while you can read another character from the string
if that character is "(", push the current position onto the stack
if that character is ")", pop a position from the stack
# you've reached the end of the string now
if the stack is empty, there is no match
else the top of the stack is the position of the last unmatched parenthesis;
take a substring from there to the end of the string
Run Code Online (Sandbox Code Playgroud)
然后获取第一个未使用的逗号的所有内容,您可以再次执行该结果:
nestingLevel = 0
while you can read another character from the string
if that character is "," and nestingLevel == 0, stop
if that character is "(" increment nestingLevel
if that character is ")" decrement nestingLevel
take a substring from the beginning of the string to the position at which
you left the loop
Run Code Online (Sandbox Code Playgroud)
这两个短循环对于其他人来说将更容易理解,并且比正则表达式解决方案(至少一个没有递归)更灵活.