DOS/Windows的文件名通配符,比如:*.txt,我们可能很熟悉。介绍一个更强的—正则表达式。
一、正则表达式
正则表达式(regular expression,或简称regex ),是一种字符串查找的语言,一个正则表达式,就是用某种模式去匹配一类字符串的一个公式。
举几个例子吧:
正则表达式 “r.t”,其中 . 表示任意一个字符(如同DOS的通配符 ?) ,可以在字符串 “rat rot rpt”中匹配出 rat rot rpt
正则表达式 “r[aou]t”,可以在字符串 “rat rot rpt”中匹配出 rat rot,但不能匹配出rpt,因为表达式中规定第二个字符只能是a,o,u
正则表达式这个概念最初是由Unix中的工具软件(例如sed、grep及vi)普及开的。
很多人因为它们看上去比较古怪而且复杂所以不敢去使用,但它的功能很强。
在Unix中,用grep,可以用一个正则表达式一次性对文件进行批量文字操作,比如:删除空格行、更改函数参数等等,够强不。
关于它的详细解释和用途,大家可以在网上搜一下,很多。
二、C语言实现
虽然很多开发工具都提供了正式表达式的支持库。但我还是想自己整一个。
在网上找到著名的Henry Spencer的regex library源码(http://www.arglist.com/regex/files/regexp.old.tar.Z)。
Henry Spencer 1986年第一次写的,用纯C写的,很好移植,很多后来的regex实现都参考它。
库中有几个函数和数据结构,用起来有一些麻烦,要花一段时间去摸索。
于是,我把它包装了一下,以方便使用。就二个纯C文件(JRegex.h,JRegex.c),可移值,不依赖于任何第三方代码。
其中:开发了几个非常简单的函数:
//查找函数, 用正则表达式regex_expression,int 在string中匹配查找
//找到则返回1, start是找到的开始的位置,length是找到的长度
int RegexFind(char *string, char * regex_expression,int *start, int *length);
//替换函数, 用正则表达式regex_expression,int 在string中匹配查找
//找到用replace_regex_expr,替换,start是找到的开始的位置,length是替换的长度
//成功则返回1,失败返回0
int RegexReplace(char *string,char * find_regex_expr,char * replace_regex_expr, int *start,int *length);
//从string中抽取子串,子串从start开始,长度为length
//此函数用malloc()生成返回字符串所需的内存,用完后记得要free()
char * ExtractString(char *string, int start, int length);
用法很简单:
(一)Regex查找示例
char *string;
char *find_regex_expr; //查找用的正则表达式
char *find_string; //查找到的子串
int start; //查找到的子串的起始位置
int length; //子串的长度
string=malloc(256);
strcpy(string,”rat rot rpt”);
find_regex_expr=”r[aou]t”; //意思是三个字符r?t, 第二个字符只能是a,o,u之一
printf(“RegexFind Example: string=%s, regex=%s/n”,string,find_regex_expr);
//Regex查找示例
while (1==RegexFind(string,find_regex_expr,&start, &length))
{
//找到后,从string截取出子串
find_string=ExtractString(string, start, length);
if (find_string!=NULL)
{
printf(“Found %s/n”, find_string);
free(find_string); //由于ExtractString时申请了内存,此处释放子串内存
}
string=string+length; //将指针指向下一个位置,以便继续查找
}
返回结果为:
RegexFindExample: string=rat rot rpt, find_regex=r[aou]t
Found rat
Found rot
(二)替换示例
strcpy(string,”rat rot rpt”);
old_string=string; //保存字串的起始位置
find_regex_expr=”r([aou])t”; //意思是三个字符r?t, 第二个字符只能是a,o,u之一
// 其中 ( ) 的含义是把其中找到的字符编成一个组,在替换中可用 /1 来获得
replace_regex_expr=”r//1//1t”; //替换为 r??t, 把第二个字符重复一遍
printf(“RegexReplace Example: string=%s, find_regex=%s, replace_regex=%s/n”,
string,find_regex_expr,replace_regex_expr);
while (1==RegexReplace(string,find_regex_expr,replace_regex_expr,&start, &length))
{
//找到后,从string截取出子串
find_string=ExtractString(string, start, length);
if (find_string!=NULL)
{
printf(“Replace with %s/n”, find_string);
free(find_string); //由于ExtractString时申请了内存,此处释放子串内存
}
string=string+length; //将指针指向下一个位置,以便继续替换
}
printf(“String after replace: %s”,old_string); //显示完成替换后的字串
运行结果为:
RegexReplace Example: string=rat rot rpt, find_regex=r([aou])t, replace_regex=r/1/1t
Replace with raat
Replace with root
String after replace: raat root rpt
三、DOS/Windows的文件名通配符
文件名通配符 ? 和 * , 大家可能很熟悉了。如何在程序用实现通配符的功能、实现文件名的筛选呢?
这里介绍一个利用正则表达式的实现方式。
原理: 把包含通配符 ? 和 * 转换为等价的正则表达式,搜索即可。
比如: a?b.txt 转化为正则表达式 a.b/.txt
*.txt 转化为正则表达式 .*/.txt
具体来说:
* 变成 .*
? 变成 .
特殊字符,如:, / / { } ( )等,前面加一个 / 号。
我的JRegex.c中包装了两个函数:
//转换函数, 将通配符表达式转换为正则表达式
//此函数用malloc()生成返回字符串所需的内存,用完后记得要free()
char *WildCharToRegex(char *wild_char_string);
//通配符查找函数,用通配符表达式find_expression在string中匹配查找
//找到则返回1, start是找到的开始的位置,length是找到的长度
//事实上,这个函数是先调用WildCharToRegex,再调用RegexFind。
int DosWildCharFind(char *string, char * find_expression,int *start, int *length);
(一)转换示例
char *string;
char *find_expression; //查找用的通配符表达式
char *regex_expression; //正则表达式
int start; //查找到的子串的起始位置
int length; //子串的长度
string=malloc(256);
strcpy(string,”hello.txt”);
find_expression=”*.txt”;
//转换为regex的示例
regex_expression=WildCharToRegex(find_expression);
printf(“/nWildchar Expression: %s /n”,find_expression);
printf(“Regex Expression: %s /n”,regex_expression);
free(regex_expression); //由于WildCharToRegex时申请了内存,此处释放内存
(二)查找/匹配示例
//直接用通配符表达式查找/匹配
printf(“String %s /n”,string);
if (1==WildCharFind(string, find_expression, &start, &length))
{
printf(“Found %s at %d /n”,find_expression,start);
}
else
{
printf(“Not find %s /n”,find_expression);
}
运行结果为:
Wildchar Expression: *.txt
Regex Expression: .*/.txt
String hello.txt
Found *.txt at 0
四、应用软件对正则表达式的支持
Unix是正则表达式的原发地,grep, vi, sed, perl 都支持正则表达式。
Microsoft Word, Excel是不支持正则表达式的,它们支持一些特定的表达符,比如: ^p表达
这个实现起来很简单,就是在查找串中把 ^p 换成换行符即可。
VS.net支持正则表达式。
五、小结
正则表达式是一个很强的工具。有了它,可以在你的软件中增强查找、替换、匹配等功能。
本文提供的 JRegex.c 封装了Henry Spencer的Regex库(ANSI C),可移植到任何系统上。
为尊重原作者的版权要求,请在使用时声明 源码来源于Henry Spencer, 由JoStudio封装。
BLOG主页: http://blog.csdn.net/c80486
具体源码可在我的资源库中下载