写这个的初衷是为了完成目下我自己遇到的需求,需要把部分linux下工作的c代码迁移到windows环境下,并以dll库的形式提供。函数需要增加如下声明
__declspec(dllexport) void func( void * arg)
/* __declspec(dllexport) 在后续我直接宏定义为了类似 WIN_DECLARE 的格式*/
我便考虑以正则表达式的形式,自动匹配到函数段,并在函数名的前面增加声明,但函数名可能存在很多种的形式,希望匹配到所有情况不太现实,我主要编写正则表达式适配了以下两种函数声明和实现的情况。
/*函数声明1*/
void func( void * arg);
/*函数声明2*/
void func( void * arg1 , void * arg2 ,
void * arg3);
/*函数实现1*/
void func( void * arg)
{
...
}
/*函数实现2*/
void func( void * arg1 , void * arg2 ,
void * arg3)
{
...
}
针对上述函数声明1的情况,可以用如下正则进行一个简单的匹配,我使用sed命令
sed 's/^\w.*([^()]*);$/WIN_DECLARE &/g;' test.c
从左到右,分四部分简单说明一下这个表达式
针对其他几种情况,也列举正则表达式如下,但是与如上这种均是大同小异。
/*for 声明2*/
sed 's/^\w.*([^()]*,$/WIN_DECLARE &/g;' test.c
/*for 实现1*/
sed 's/^\w.*([^()]*)$/WIN_DECLARE &/g;' test.c
/*for 实现2*/
sed 's/^\w.*([^()]*,$/WIN_DECLARE &/g;' test.c
用如上的表达式可以自动过滤出绝大部分的函数,并加上对应的声明。
不过这里我可能要考虑几种更细致的处理。
WIN_DECLARE WIN_DECLARE void func( void * arg)
这是为了保持该表达式的自身的强壮性,因为我可能最终会对一个文件夹中的所有文件都使用该命令,而使用过后,我可能又会往文件夹添加新的文件。故而需要保证已经调整过的文件仍能正常工作。
针对该需求,可以在每次执行表达式前,先把WIN_DECLARE清除掉,使用 sed 的多表达式功能来完成。sed命令可以使用 -e 来在一次匹配中,以从左到右的顺序先后使用表达式来做过滤。具体如下
sed -e 's/^WIN_DECLARE[ \t]*//g' -e 's/^\w.*([^()]*);$/WIN_DECLARE &/g' test.c
上述表达式比较简单,就是以 WIN_DECLARE 开头,后面若干个 空格或者tab 均匹配,然后替换掉,完成一步预处理,然后再执行后面的正则匹配。
我了解一下资料,发现sed的一种特殊表达式可以满足需求,即取反的组合表达式,列举如下:
sed -e '/.*static.*([^()]*)$/! s/^\w.*([^()]*)$/WIN_DECLARE &/g' test.c
因为一般static的声明只在c的函数实现中有,故而我这里的例子是针对上面的函数实现1的。后半段与前面是一致的,主要在于如下的前半段
/.*static.*([^()]*)$/!
这也是属于一个表达匹配式中的一部分,然后是匹配到这一行的开头部分带有 static字段,static 前后均可以有任意数量的字符,同时后段匹配 我们对函数实现的 正则表达式匹配,即匹配 ([^()]*)$ ,我们就认为这是static声明的函数,而这种函数显然是内部使用,不需要通过 dllexport的声明暴露出来,故而在表达式的末尾使用 ‘!’ 来取非,意味着我们后面匹配的表达式的前提,是不匹配这前半段的表达式。
将上述的几个流程综合在一起,单独针对函数实现1 这种情况,我们可以得到如下的表达式。
sed -e 's/^WIN_DECLARE[ \t]*//g' -e '/.*static.*([^()]*)$/! s/^\w.*([^()]*)$/WIN_DECLARE &/g' test.c
当然,我们也可以把函数实现1和 函数实现2这两种情况,用sed的 -e 多表达式来实现。在处理上效率会更高。
sed -e 's/^WIN_DECLARE[ \t]*//g' -e '/.*static.*([^()]*)$/! s/^\w.*([^()]*)$/WIN_DECLARE &/g' -e '/.*static.*([^()]*,$/! s/^\w.*([^()]*,$/WIN_DECLARE &/g' test.c
这几乎是我写过的最长的正则表达式组合语句。完成之后我也想到,这种思路可能在其他地方也可以应用上。关键点就是我在标题中描述两个点,一是多表达式应用,二是通过sed实现过率特定格式的办法。故而我撰写了这篇博客,也算完成一个任务,同时也是我第一次对正则表达式做这种相对复杂的应用,故而特此记录一下。
备注:
实际对文件做修改,当然要需要使用 sed -i 选项,但是使用这个选项务必慎重,在此,为避免出现错误,在举例的表达式中均不使用 -i选项。