如何使用正则表达式获取函数声明或定义

时间:2009-06-03 06:45:13

标签: python regex

我想只获得像

这样的函数原型
int my_func(char, int, float)
void my_func1(void)
my_func2()

使用regex和python从C文件中获取。

以下是我的正则表达式格式:".*\(.*|[\r\n]\)\n"

7 个答案:

答案 0 :(得分:6)

这是我为这些任务编写的一个方便的脚本,但它不会给出函数类型。它仅适用于函数名称和参数列表。

# Exctract routine signatures from a C++ module
import re

def loadtxt(filename):
    "Load text file into a string. I let FILE exceptions to pass."
    f = open(filename)
    txt = ''.join(f.readlines())
    f.close()
    return txt

# regex group1, name group2, arguments group3
rproc = r"((?<=[\s:~])(\w+)\s*\(([\w\s,<>\[\].=&':/*]*?)\)\s*(const)?\s*(?={))"
code = loadtxt('your file name here')
cppwords = ['if', 'while', 'do', 'for', 'switch']
procs = [(i.group(2), i.group(3)) for i in re.finditer(rproc, code) \
 if i.group(2) not in cppwords]

for i in procs: print i[0] + '(' + i[1] + ')'

答案 1 :(得分:2)

查看你的C编译器是否有一个选项来输出一个只是它正在编译的原型的文件。对于gcc,它是-aux-info FILENAME

答案 2 :(得分:1)

我认为正则表达式不是您的最佳解决方案。有许多陷阱,如注释,字符串中的文本等,但如果您的函数原型共享共同的样式:

type fun_name(args);

然后\w+ \w+\(.*\);应该适用于大多数情况:

mn> egrep "\w+ \w+\(.*\);" *.h
md5.h:extern bool md5_hash(const void *buff, size_t len, char *hexsum);
md5file.h:int check_md5files(const char *filewithsums, const char *filemd5sum);

答案 3 :(得分:1)

我认为这个应该做的工作:

r"^\s*[\w_][\w\d_]*\s*.*\s*[\w_][\w\d_]*\s*\(.*\)\s*$"

将扩展为:

string begin:   
        ^
any number of whitespaces (including none):
        \s*
return type:
  - start with letter or _:
        [\w_]
  - continue with any letter, digit or _:
        [\w\d_]*
any number of whitespaces:
        \s*
any number of any characters 
  (for allow pointers, arrays and so on,
  could be replaced with more detailed checking):
        .*
any number of whitespaces:
        \s*
function name:
  - start with letter or _:
        [\w_]
  - continue with any letter, digit or _:
        [\w\d_]*
any number of whitespaces:
        \s*
open arguments list:
        \(
arguments (allow none):
        .*
close arguments list:
        \)
any number of whitespaces:
        \s*
string end:
        $

匹配所有可能的组合并不完全正确,但在更多情况下应该有效。如果您希望它更准确,请告诉我。

编辑: 免责声明 - 我对Python和Regex都很陌生,所以请放纵;)

答案 4 :(得分:1)

有很多陷阱试图用正则表达式“解析”C代码(或者至少提取一些信息),我肯定会为你最喜欢的解析器生成器借用一个C(比如Bison或者Python的替代方案,在任何地方都有C语法作为例子)并在相应的规则中添加动作。

另外,不要忘记在解析之前在文件上运行C预处理器。

答案 5 :(得分:0)

下面的正则表达式还考虑了析构函数或const函数的定义:

^\s*\~{0,1}[\w_][\w\d_]*\s*.*\s*[\w_][\w\d_]*\s*\(.*\)\s*(const){0,1}$

答案 6 :(得分:0)

我建立在Nick Dandoulakis的answer上,用于类似的用例。我想在glibc中找到socket函数的定义。这会在名称中找到一堆带有“socket”的函数,但找不到socket,突出显示了许多其他人所说的内容:可能有更好的方法来提取这些信息,比如编译器提供的工具。

# find_functions.py
#
# Extract routine signatures from a C++ module
import re
import sys

def loadtxt(filename):
    # Load text file into a string. Ignore FILE exceptions.
    f = open(filename)
    txt = ''.join(f.readlines())
    f.close()
    return txt

# regex group1, name group2, arguments group3
rproc = r"((?<=[\s:~])(\w+)\s*\(([\w\s,<>\[\].=&':/*]*?)\)\s*(const)?\s*(?={))"
file = sys.argv[1]
code = loadtxt(file)

cppwords = ['if', 'while', 'do', 'for', 'switch']
procs = [(i.group(1)) for i in re.finditer(rproc, code) \
 if i.group(2) not in cppwords]

for i in procs: print file + ": " + i

然后

$ cd glibc
$ find . -name "*.c" -print0 | xargs -0 -n 1 python find_functions.py | grep ':.*socket'
./hurd/hurdsock.c: _hurd_socket_server (int domain, int dead)
./manual/examples/mkfsock.c: make_named_socket (const char *filename)
./manual/examples/mkisock.c: make_socket (uint16_t port)
./nscd/connections.c: close_sockets (void)
./nscd/nscd.c: nscd_open_socket (void)
./nscd/nscd_helper.c: wait_on_socket (int sock, long int usectmo)
./nscd/nscd_helper.c: open_socket (request_type type, const char *key, size_t keylen)
./nscd/nscd_helper.c: __nscd_open_socket (const char *key, size_t keylen, request_type type,
./socket/socket.c: __socket (int domain, int type, int protocol)
./socket/socketpair.c: socketpair (int domain, int type, int protocol, int fds[2])
./sunrpc/key_call.c: key_call_socket (u_long proc, xdrproc_t xdr_arg, char *arg,
./sunrpc/pm_getport.c: __get_socket (struct sockaddr_in *saddr)
./sysdeps/mach/hurd/socket.c: __socket (int domain, int type, int protocol)
./sysdeps/mach/hurd/socketpair.c: __socketpair (int domain, int type, int protocol, int fds[2])
./sysdeps/unix/sysv/linux/socket.c: __socket (int fd, int type, int domain)
./sysdeps/unix/sysv/linux/socketpair.c: __socketpair (int domain, int type, int protocol, int sv[2])

就我而言,thisthis可能会对我有所帮助,除非我似乎需要阅读汇编代码以重用其中描述的策略。