“提取c程序注释”,这是一个典型的状态机问题,但在此我想用正则表达式(regExp)工具来解决。
perl的正则表达式很强,起初我想到“多行匹配”,将c文件整个读入一个串变量,然后逐个抽取/*块注释*/。这可能需要使用选项 /m /g ,还得考虑行注释和块注释符的混合情况,是个棘手的问题。
初次尝试 发现一个大问题: 匹配最大串还是最小串?
# perl 5.12
# // 行注释
# /* */ 块注释
# 识别错误的原因:匹配最大串 /*comment1*//*comment2*/
open(ifp, "comments.txt") || die ("canot open file.");
$/=undef; # 吞噬
$cnt=0;
while($line = <DATA>)
{
$line =~ /\/\*.*\*\//s;
printf("line%2d:%s", $cnt++, $&);
}
__DATA__
/*comment1*/
int sum(int a, int b)
{
return a+b;
}
/*comment2*/
|
对于模式 /\/\*.*\*\//s 我期望它匹配 /*comment1*/ ,但它却匹配了 /*comment1*/ ... /*comment2*/. 有没有一种方法可以成对匹配?
有。模式对 /\/\*/ ... /\*\// 将成对匹配 /* 和 */。
据推测,模式对 /pattern1/.../pattern2/的工作过程大致如下:
bool sw=off;
if(sw==off)
{
if(line match /pattern1/)
sw=on;
}
else
{
do something, like print~
if(line match /pattern1/)
sw=off;
}
if(sw == on)
do something.
能够识别行注释和块注释的正则式式perl如下:
# // 行释
# /* 块注释 */
# 注:要求代码与注释分行,因为正则以行为单位匹配。
# 可用格式化工具(ArtisticStyle)将代码与注释分行。
# 特点:识别出的注释保持缩进。
use strict;
use warnings;
my $cnt=0;
my $str;
my $bMultiLine=0;
while (<DATA>)
{
#print "$_";
$cnt++;
$str = $_;
# 单行内的注释
if(!$bMultiLine)
{
# 行注释(要求与代码不在同一行,可用格式化工具将代码与注释分行)
if (/\s*\/\//)
{
print "$cnt S:";
print;
next; # skip
}
if (/\/\*.*\*\//) # 只占一行的块注释
{
print "$cnt B:";
print;
next; # skip
}
}
# 跨行的块注释
if (/\/\*/ ... /\*\//) # /* ... */
{
print "$cnt M:";
print;
$bMultiLine=1;
}
if($bMultiLine)
{
if(/.*\*\//)
{
$bMultiLine = 0;
}
}
}
__DATA__
行注释
// this is a line comment
// this is a line /* comment * /
块注释(只占一行)
/* this is a block comment, in one line. */
/* this is a block comment, // in one line. */
块注释(跨行)
/*
this is a block comment, in multi-line.
*/
块注释中的//属于注释内容
/* this is a
block comment, but
// not a line comment */
块注释中的/*属于注释内容
/* this is a
/* block
/* comment */
块注释不能嵌套,如下面是非法的块注释
/*
illegal comment, because
/* nest... */
ing
*/
void SetPwm(unsigned long m) // 这个行注释与代码在同一行,再与块注释符混合 /* 用regExp难以识别它。 */
{
printf("hi!");
}
|
它有一点不足:以行匹配。这要求注释与非注释不能在同一行,这个要求不免苛刻。至于是否可用正则的位置变量、预见性匹配等技巧来解决此问题,我没有更多的想法。 “提取c程序注释”的一种更实用和明了的方法是使用状态机思想,见[状态机示例-提取c程序注释]