5

我正在研究一个正则表达式来识别 C 中的变量声明,我已经得到了这个。

[a-zA-Z_][a-zA-Z0-9]*

有没有更好的解决方案?

4

6 回答 6

11

一种识别C 中变量声明的模式。查看常规声明,我们看到:

int variable;

如果是这种情况,应该在任何事情之前测试type关键字,以避免匹配其他内容,例如使用预处理器定义的字符串或常量

(?:\w+\s+)([a-zA-Z_][a-zA-Z0-9]+)

变量名位于 \1 中。

您需要的功能是look-behind/look-ahead。

2015 年 7 月 11 日更新

前面的正则表达式无法将某些变量与 _中间的任何位置匹配。要解决这个问题,只需将 添加_到第一个捕获组的第二部分,它还假定变量名具有两个或多个字符,这是修复后的样子:

(?:\w+\s+)([a-zA-Z_][a-zA-Z0-9_]*)

然而,这个正则表达式有很多误报,goto jump;作为其中之一,坦率地说它不适合这项工作,正因为如此,我决定创建另一个正则表达式来涵盖更广泛的情况,虽然它远非完美,这里是:

\b(?:(?:auto\s*|const\s*|unsigned\s*|signed\s*|register\s*|volatile\s*|static\s*|void\s*|short\s*|long\s*|char\s*|int\s*|float\s*|double\s*|_Bool\s*|complex\s*)+)(?:\s+\*?\*?\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*[\[;,=)]

我已经用 Ruby、Python 和 JavaScript 测试了这个正则表达式,它在常见情况下效果很好,但在某些情况下会失败。此外,正则表达式可能需要一些优化,尽管很难在保持跨多个正则表达式引擎的可移植性的同时进行优化。

测试简历

unsignedchar *var;                   /* OK, doesn't match */
goto **label;                        /* OK, doesn't match */
int function();                      /* OK, doesn't match */
char **a_pointer_to_a_pointer;       /* OK, matches +a_pointer_to_a_pointer+ */
register unsigned char *variable;    /* OK, matches +variable+ */
long long factorial(int n)           /* OK, matches +n+ */
int main(int argc, int *argv[])      /* OK, matches +argc+ and +argv+ (needs two passes) */
const * char var;                    /* OK, matches +var+, however, it doesn't consider +const *+ as part of the declaration */
int i=0, j=0;                        /* 50%, matches +i+ but it will not match j after the first pass */
int (*functionPtr)(int,int);         /* FAIL, doesn't match (too complex) */

误报

以下情况很难用可移植的正则表达式覆盖,文本编辑器使用上下文来避免突出显示引号内的文本。

printf("int i=%d", i);               /* FAIL, match i inside quotes */

误报(语法错误)

如果在应用正则表达式之前测试源文件的语法,则可以解决此问题。使用 GCC 和 Clang,可以只传递 -fsyntax-only 标志来测试源文件的语法,而无需编译它

int char variable;                  /* matches +variable+ */
于 2012-10-21T00:29:16.250 回答
3
[a-zA-Z_][a-zA-Z0-9_]{0,31} 

这将允许您将变量名称作为“m_name”验证。

于 2013-11-20T15:53:00.243 回答
1

这将消除 return 和 typedef 错误标志。它能够捕获返回类型和变量名,并支持指针和数组。除了检测 typedef 变量之外,它还消除了注释代码,进一步减少了错误标志。

^\s*(?!return |typedef )((\w+\s*\*?\s+)+)+(\w+)(\[\w*\])?(\s*=|;)
于 2016-02-16T18:34:20.227 回答
1

我设计了这个字符串以在我的作业中匹配正则表达式:

(_?[a-zA-Z0-9_]+)(\s+)(([a-zA-Z]?_[a-zA-Z])?([a-zA-Z]*[0-9]*_*)(=[a-zA-Z0-9]*)?[,]?)+((\s+)(([a-zA-Z]?_[a-zA-Z])?([a-zA-Z]*[0-9]*_*)(=[a-zA-Z0-9]*)?[,]?))*

它匹配所有声明,包括using namespace std. 因此,您需要在检查 group1 的数据类型之前删除关键字。如果数据类型有效,您可以删除 group1 字符串,并且只剩下逗号分隔的变量,包括带有赋值运算符的变量。

以下代码也正确匹配:

int a=3, b=9, c, N

Even int i=0 在 for 循环中匹配: for(int i=0; i<N; ++i)

这个正则表达式字符串确实需要您在过滤方面做更多的工作(例如在检查之前删除关键字),但反过来,在其他正则表达式字符串失败的情况下匹配。编辑:忘了提到它也检测_字母数字声明的所有组合。

EDIT2:对正则表达式字符串进行轻微修改:

([a-zA-Z0-9_]+)(\\s+)(([a-zA-Z_\\*]?[a-zA-Z0-9_]*(=[a-zA-Z0-9]+)?)[,;]?((\\s*)[a-zA-Z_\\*]?[a-zA-Z0-9_]*?(=[a-zA-Z0-9]+)?[,;])*)

这匹配所有变量和方法声明。因此,您需要做的就是检查是否reg_match->str(1)是数据类型。如果是,您可以使用sregex_token_iterator(带有正则表达式分隔符(\\s*)[,.;](\\s*)) onreg_match->str(3)来获取所有用户定义的标识符。

于 2016-10-02T20:12:41.603 回答
0

Zac Howard-Smith 改进的答案版本,删除了尾随空格,支持带有逗号分隔符和可选类型定义的多个变量。

^[ \t]*(?!return|typedef)((\w+[ \t,]*\*?[ \t,]+)+)*(\w+)(\[\w*\])?([ \t,]*=|;)
于 2021-09-05T23:11:29.647 回答
-2

这是变量名的完整形式。

只需稍作修改,您可以根据需要使用多个_

([a-zA-Z_][a-zA-Z0-9]*)*
于 2016-06-06T17:17:38.087 回答