本文并不对打算正则表达式的用法进行详细解析,通过google可以找到很多相关教程,只是通过一个实例展示正则表达式的强大功能。
案例:很多通讯系统,在长期的运行过程中,难免会遇到很多异常,为了定位错误原因,一个通常的方法就是给每种错误或者每个出错误的地方分配一个唯一的错误码,然后将这个错误码发送到后台,分析者可以根据这个错误码提供的附加信息,定位异常原因,解决故障。错误码和附加信息的对应关系通常被写入到一个INI配置文件中。现在我们就需要根据errorcode头文件内容建立二者的对应关系。
定义错误宏的头文件一般是这样的形式:
#define cmeProgramErrs_M (WORD)0 /*代码逻辑错误*/
#define cmeUnexpState_M (WORD)(cmeProgramErrs_M + 1) /*不期望的程序状态*/
#define cmeUnexpNullPointer_M (WORD)(cmeProgramErrs_M + 2) /*不期望的空指针*/
#define cmeConfigErrs_M (WORD)500 /*配置错误*/
#define cmeSysCapCfgErr_M (WORD)(cmeConfigErrs_M + 1) /*系统能力配置错误*/
其中错误的原因,直接用数字定义会根据类型分段,每段有一个基址,具体的错误原因会在基址上递增。最终生成的二者对应关系的INI配置文件应该如下面的形式:
1=cmeUnexpState_M(不期望的程序状态)
2=cmeUnexpNullPointer_M(不期望的空指针)
501=cmeSysCapCfgErr_M(系统能力配置错误)
最原始的方法当然是拷贝复制,从头文件中拷贝相关字段到INI文件中。当然,也可以自己编写C语言程序,分别寻找相应的标志字段,拆出每个字段,同时建立错误段基址的宏和其数值的对应关系,然后计算每个错误码,将对应关系写道INT文件中。这样的处理,听起来就比较麻烦,有没有比较好的方法?
下面利用正则表达式的功能,用Perl语言完成以上功能:
#!/usr/bin/perl -w
#
# change errorcode macro head file to INI file
#
# Passed filename to handle use strict;
my %base; #声明一个关联数组
#需要处理的文件,名称从命令行输入获得
my $file = shift or die "Missing input file name!";
open(IN, "$file") or die "Opening $file: $!";
open(OUT, ">$file.ini") or die "Opening {$file}.out: $!";
# handle content
while (<IN>)
{
if (m/\s*\#define\s+(\w+)\s+\(WORD\)(\d+)/) #对于基址格式定义
{
$base{$1} = $2; #将基址加入HASH表
}
elsif (m/\s*\#define\s+(\w+)\s+\(WORD\)\(\s*(\w+)\s*\+\s*(\d+)\s*\)\s*\/\*(.*)\*\//) #对于原因格式定义
{
my $BaseValue = $base{$2}; #查询HASH表中该基址对应值
if ($BaseValue ne '')
{
my $MacroValue = $BaseValue + $3;
my $comment = $4;
print OUT "$MacroValue=$1($4)\n";
}
else
{
print "Undefined base macro. line $.: $_";
}
}
}
close(IN);
close(OUT)
从上例,正则表达式的强大可见一斑。此外,在这种文本操纵的方面,也刚好是perl的用武之地。C语言虽然强大,但是在这里确实不太方便。一个真正pragmatic的程序员,不会拘泥于具体的环境和语言,而是根据具体的情况采取最恰当的工具。
btw:对于正则表达式的详细描述可以参考Friedl的Mastering Regular Expressions