1

我正在编写一个 perl 脚本来使用正则表达式从 .h 文件中生成 .cpp 文件来查找函数,然后再次使用正则表达式将结果分成两个部分,即返回类型和函数。

我创建了一个正则表达式来查找几乎可以工作的返回类型。

^(\s*&?\w*\s*(\<{1}.*\>{1})*\s)

编辑:我将正则表达式字符串更新为效果更好的字符串,但就这个问题而言,仍然没有任何变化。

这适用于大多数 cpp 原型,例如

int funky();
int funky(int something);
&int funky(int something);
&int <vector *> funky();

在这些情况下,正则表达式匹配

int
int
&int
&int <vector *>

这是完美的,但是在函数参数内部存在匹配的字符串的情况下,例如:

int <vector> funky(int <vector> i);
int <vector> funky(int <vector *> i);
int <vector> funky(const int <vector> i);

正则表达式匹配

int <vector> funky(int <vector>
int <vector> funky(int <vector *>
int <vector> funky(const int <vector>

当我希望它返回时

int <vector>
int <vector>
int <vector>

而且我无法弄清楚它是否继续超过第一个右括号'>'的末尾。我是正则表达式的新手,根本无法弄清楚。

很抱歉有一个答案,我搜索并没有找到一个,可能是因为我什至不知道要查找哪些术语:(。

Edit2:如果这个问题比我预期的更复杂,有人可以解释为什么它会在第一个 <.*> 之后继续吗?我不明白为什么这不起作用。

4

3 回答 3

3

正则表达式非常适合正则语言。但是,大多数编程语言都不是规则的。任何具有某种大括号和递归的东西都是上下文无关的语言,甚至是上下文相关的。(如果这些 CS 术语让您感到困惑,请在 Wikipedia 上查找它们。它们很有用)。

尤其是 C 的语法非常复杂。

然而,Perl 的正则表达式并不局限于正则表达式。我们可以表达上下文无关文法,即定义字符串必须匹配的一组规则。在每个规则中,我们可以引用其他规则。因此,我们可以进行递归,以及匹配嵌套括号之类的事情:

m{
   ^ (?&NESTED_PAREN) $
   (?(DEFINE)
     (?<NESTED_PAREN> [(] (?: [^()]+ | (?&NESTED_PAREN) )* [)] )
   )
}x;

这个正则表达式定义了一个顶级规则:从头到尾的整个字符串必须是一个嵌套的括号。然后跟随一个DEFINE块。我们定义了一个规则NESTED_PAREN,它以 a 开头(并且可以包含任意数量的非括号字符和嵌套的括号。后面跟着一个). 必须考虑到,编写无限递归语法很容易,但幸运的是,在此示例中,每次递归都会消耗字符或失败。

对于用 Perl 编写语法的更好的界面,我强烈推荐CPAN 中的 Regexp::Grammars

现在我们知道如何在 Perl 中编写语法,并且可以为您的函数声明创建一个语法。这是一个没有空格的符号表示法:

FUNCTION ::= TYPE VECTOR? NAME '(' ARGUMENTS ')'
VECTOR   ::= '<' vector '*'? '>'
ARGUMENTS::= ( ARGUMENT (',' ARGUMENT)* )?
ARGUMENT ::= TYPE VECTOR? NAME

您可能已经注意到,我们可以在参数列表中重复使用函数的一些规则。现在您只需要将这个语法映射到一组(DEFINE)规则,编写顶级规则,就可以开始了。同样,使用 Regexp::Grammars 将使这项工作变得更加容易,但它提供了另一种您必须学习的语言。

有关Perl 正则表达式中内置功能的最终参考,请参阅perldoc perlre 。

请注意,(由于预处理器等原因),C(和 C++)语法既不是常规的也不是上下文无关的。没有执行预处理器的一切最终都会成为一个不错的尝试……</p>

于 2012-09-22T21:59:02.837 回答
2

正则表达式是贪婪的。用一个 ?跟随你的 .* 使其不贪婪,它将在第一场比赛停止,而不是最后一场比赛。

^(\s*&?\w*\s*(\<{1}.*?\>{1})*\s)

更多信息在http://perldoc.perl.org/perlre.html#Regular-Expressions

于 2012-09-22T22:39:35.523 回答
1

这是另一种方法:

/^\s*&?\w*(\s+\<[^\>]+\>)?/

括号中的部分(\s+\<[^\>]+\>)?是任何以空格开头的文本,然后是“<”,后跟任何不是“>”的字符(否定字符类[^\>]+),然后是“>”。

带有 ">" 的否定字符类确保匹配将在 <> 部分结束后立即结束。括号后面也跟着一个“?” 使其成为表达式的可选部分。

于 2012-09-23T14:32:54.013 回答