我正在使用正则表达式来识别C中的变量声明,我已经得到了这个。
[a-zA-Z_][a-zA-Z0-9]*
有没有更好的解决方案?
答案 0 :(得分:6)
在C中识别变量声明的模式。查看传统声明,我们看到:
int variable;
如果是这种情况,应该在任何事情之前测试类型关键字,以避免匹配其他内容,如字符串或使用预处理器定义的常量
(?:\w+\s+)([a-zA-Z_][a-zA-Z0-9]+)
变量名称位于\ 1。
您需要的功能是后视/前瞻。
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+ */
答案 1 :(得分:3)
[a-zA-Z_][a-zA-Z0-9_]{0,31}
这将允许您将变量名称作为“m_name”验证。
答案 2 :(得分:1)
这将消除return和typedef false标志。它能够捕获返回类型和变量名称,并支持指针和数组。除了检测typedef变量之外,它还消除了注释代码,进一步减少了错误标志。
^\s*(?!return |typedef )((\w+\s*\*?\s+)+)+(\w+)(\[\w*\])?(\s*=|;)
答案 3 :(得分:1)
我在我的作业中设计了这个字符串,用于匹配正则表达式:
#define for_loop_begin(size)\
for (int i = 0; i < size; i++) \
{ \
for (int j = 0; j < size; j++) {
#define for_loop_end\
}\
}
它匹配包括(_?[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]*)?[,]?))*
在内的所有声明。因此,在检查group1的数据类型之前,您需要删除关键字。如果数据类型有效,则可以删除group1字符串,并且只保留逗号分隔的变量,包括具有赋值运算符的变量。
以下代码也正确匹配:
using namespace std
即使
int a=3, b=9, c, N
在for循环中匹配:
int i=0
此正则表达式字符串确实需要您在过滤方面做更多工作(比如在检查之前删除关键字),但反过来,在其他正则表达式字符串失败的情况下匹配。
编辑:忘记提及它检测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*)
的正则表达式分隔符)来获取所有用户定义的标识符。
答案 4 :(得分:-2)
这是变量名称的完整形式。
如果您愿意,只需稍加修改就可以使用多个_
。
([a-zA-Z_][a-zA-Z0-9]*)*