2

我对 RegEx 有一点了解,但目前,它远远超出了我的能力。

我需要帮助才能找到最后一个没有匹配右括号的左括号之前的文本。

(用于开发中的开源软件的 CallTip。)

下面是一些例子:

--------------------------
Text               I need
--------------------------
aaa(                  aaa
aaa(x)                ''
aaa(bbb(              bbb
aaa(y=bbb(            bbb
aaa(y=bbb()           aaa
aaa(y <- bbb()        aaa
aaa(bbb(x)            aaa
aaa(bbb(ccc(          ccc
aaa(bbb(x), ccc(      ccc
aaa(bbb(x), ccc()     aaa
aaa(bbb(x), ccc())    ''
--------------------------

是否可以为这些情况编写正则表达式(PCRE)?

我得到的最好的结果是\([^\(]+$,它并不好,而且与我所需要的相反。

任何人都可以帮忙吗?

4

4 回答 4

3

在此处输入图像描述

看看这个 JavaScript 函数

var recreg = function(x) {
var r = /[a-zA-Z]+\([^()]*\)/;
while(x.match(r)) x = x.replace(r,'');
return x
}

应用此功能后,您将剩下所有不匹配的部分,它们没有右括号,我们只需要最后一个字母单词。

var lastpart = function(y) { return y.match(/([a-zA-Z]+)\([^(]*$/); }}

这个想法是像使用它一样

 lastpart(recreg('aaa(y <- bbb()'))

然后检查结果是否为空,否则取匹配组result[1]。大多数正则表达式引擎不支持?R递归正则表达式匹配所需的标志。

请注意,这是一个模拟递归正则表达式的示例 JavaScript 表示。阅读http://www.catonmat.net/blog/recursive-regular-expressions/

于 2013-06-06T04:28:58.670 回答
1

这适用于所有示例字符串:

\w+(?=\((?:[^()]*\([^()]*\))*[^()]*$)

最有趣的部分是:

(?:[^()]*\([^()]*\))*

它匹配零个或多个平衡的括号对以及它们之前和之间的非括号字符(如示例字符串中的y=bbb()and bbb(x), ccc())。完成该部分后,final[^()]*$确保在字符串结尾之前没有更多的括号。

但是请注意,这个正则表达式是基于这样一个假设,即永远不会有超过一层的嵌套。换句话说,它假设这些是有效的:

aaa()
aaa(bbb())
aaa(bbb(), ccc())

...但这不是:

aaa(bbb(ccc()))

您的示例中的字符串ccc(bbb(aaa(似乎暗示确实允许多级嵌套。如果是这种情况,您将无法单独使用正则表达式解决您的问题。(当然,一些正则表达式支持递归模式,但即使按照正则表达式标准,语法也是可怕的。我保证在你写完它一周后你将无法阅读你自己的正则表达式。)

于 2013-06-06T04:58:31.770 回答
0

部分解决方案 - 这是假设您的正则表达式是从可以循环的编程语言中调用的。

1)修剪输入:找到匹配的括号,并删除它们之间的所有内容。继续前进,直到没有匹配。正则表达式会寻找([^()])- 左括号,而不是括号,右括号。它必须是“查找和替换”循环的一部分。这修剪“从内到外”。

2)修剪后,你要么没有括号,要么只剩下前导/尾随的括号。现在你必须在一个左括号之前找到一个单词。这需要一个像\w(. 但如果有多个未闭合的括号,这将不起作用。取最后一个可以通过贪婪匹配来完成(在最后一个周围分组\w):^.*\w(“尽可能多的字符,直到括号前的一个单词” - 这将找到最后一个。

我说的是“近似”解决方案,因为根据您使用的环境,您如何说“此匹配组”以及是否需要在()变化之前放置反斜杠。我忽略了这个细节,因为它很难在我的 iPhone 上检查。

我希望这能激发您或其他人想出一个完整的解决方案。

于 2013-06-06T03:14:47.200 回答
0

不确定您为此使用哪种正则表达式语言/平台,也不知道您的平台是否允许使用子模式。但是,以下两步 PHP 代码将适用于您上面列出的所有情况

$str = 'aaa(bbb(x), ccc()'; // your original string

// find and replace all balanced square brackets with blank
$repl = preg_replace('/ ( \( (?: [^()]* | (?1) )* \) ) /x', '', $str);

$matched = '';
// find word just before opening square bracket in replaced string
if (preg_match('/\w+(?=[^\w(]*\([^(]*$)/', $repl, $arr))
   $matched = $arr[0];
echo "*** Matched: [$matched]\n";

现场演示:http: //ideone.com/evXQYt

于 2013-06-06T04:29:09.057 回答