-
c语言入门之在C++ Builder6上使用Boost正则表达式库
正则表达式是一种模式匹配形式,它通常用在处理的文本程序中。比如我们经常使用的grep工具,还是perl语言都使用了正则表达式。传统的C++处理正则表达式是非常麻烦的,这也成为很多其他语言爱好者的笑柄,现在情况不一样了,因为有了boost。
Boost是一个基于Template的开发源代码库,在这个库中有很多子库用来高效处理各方面的问题,比如字符串拆分,格式化,线程等等,Boost对于每一个C++爱好者都是应该了解的,对于C++ Builder用户如果能在熟练使用VCL的情况下再熟练使用Boost,我想一定如虎添翼。
一般来说,使用Boost是非常简单,和使用其他STL库没有太大区别,但使用Boost的正则表达式库则不那么容易,因为这个库还需要我们单独编译,下面我将详细介绍如何使用。
如果你还不知道或者还没有Boost的话,你可以去www.boost.org下载最新版本,作者使用的是1.30版本。将下载下来的zip包[1]解压到任何你喜欢的目录,比如D:\boost。
编译正则表达式库
前面已经提到,这个库需要我们单独编译才能使用,为什么不编译好一起发布呢?主要是考虑到不同的编译器需要不同的链接库文件和链接库太大了。在命令行下,进入[%Boost]\Libs\RegEx\Build目录,直接敲入make –fbcb6.bat命令开始编译,这里请大家注意了,如果你的计算机上同时安装了BCB5,请一定要把path设置成为BCB6的bcc32.exe程序所在的目录,否则可能使用BCB5的make程序,这样虽然能编译但最后不能使用。
编译过程相当耗时,你需要耐心等待,最终编译完成,会在[%Boost]\Libs\RegEx\Build目录生成一个BCB6目录,在这个目录生成了很多lib文件和dll文件,把所有dll文件复制到windows系统目录,所以lib文件复制到bcb6\lib目录。如果你不想这么麻烦的复制文件,可以在编译时加入install参数,就像这样make –fBcb6.bat install,不过作者还是比较喜欢前一种方式,这样我可以知道到底生成了什么文件。现在编译已经完成了,你可以体现boost的神奇魅力了。
一个测试程序
在BCB6中创建console程序,编写下列代码:
#include<deque>
#include<iostream>
#include<algorithm>
#include<boost/regex.hpp>
int main()
{
using namespace boost;
using namespace std;
regex expression("\\s+href\\s*=\\s*\"([^\"]*)\"",regbase::normal|regbase::icase);
string s="<a href=\"index.html\"><img src=\"logo.gif\"></a>";
deque<string> result;
regex_split(std::back_inserter(result),s,expression);
copy(result.begin(),result.end(),ostream_iterator<string>(cout,"\n"));
int c;
cin>>c;
return 0;
}
设置BCB6 Project属性的Lib Path和Include Path为你安装boost的目录,运行你会看到结果:
index.html
可以看到index.html已经从字符串中提出出来了,那么为什么会是这样呢?
代码的核心部分是:
regex expression("\\s+href\\s*=\\s*\"([^\"]*)\"",regbase::normal|regbase::icase);
它用来设置如何匹配字符串,上面乱七八糟的字符串很难看懂,如果不了解正则表达式的书写规则,上面代码可以和天书媲美。
regbase::normal|regbase::icase 是解析参数设置,具体可以参考boost帮助文档。
正则表达式的书写规则
具体的书写规则,大家可以参看boost的文档,我这里做一下简要说明:
. (dot)
用来匹配任何一个字符,但不包括新行上的字符
*
闭包,任意有限次的自重复连接
+
有限次自重复连接,但至少出现一次
{}
指定可能的重复次数
例如:
ba* 匹配 b ba baa baaa等
ba+ 匹配 ba baa baaaaaaaaa等
ba{1,5} 匹配 ba baa baaa baaaa baaaaa
\
转义字符,有很多用途,根据参数设置而变化,最常见的就是类似于c语言\的用法
\s
匹配空格
\w
匹配一个单词
\d
匹配数字
()
有两种用法:
1是合并的作用,例如(ab)*匹配ab abab ababab等
2是确定匹配,也就是说在()中的字符将被最终拆解出来
根据上面这张表,我们可以很容易知道前面的那段天书如何解释。
一个实际的例子
前一段时间在CSDN上有一篇帖子,问题是有一种文件结构如(类似):
@People{
Age=19
Speek=”Hay,{name},how are you”
}
问如何拆分字符串得到@后面的名字,=两边的属性名和属性值,引号里{}种的名字。
解决这个问题用正则表达式再合适不过了。
根据分析,我们可以这样构造匹配规则:
"@(.*?)\s*\\{" 匹配@开始的字符创,后面两种类型如何构造匹配规则留给大家思考吧。
这样我们可以轻易拆解这个例子。
性能分析
通过上面的讨论,大家已经了解到boost的强大威力,那个性能又如何呢?为此我们再实际来拆分一个复杂的html代码,看看到底需要花费多少时间。
为了节省篇幅,这里就不列出html代码了,不过可以告诉大家,这是一个又Word生成的大小为186K的html文件,这个文件中用到了很多<table>标签,所以我这里测试就来拆分所有<table>标签的width属性。测试代码如下:
#include<deque>
#include<iostream>
#include<algorithm>
#include<boost/regex.hpp>
#include<vcl.h>
int main()
{
using namespace boost;
using namespace std;
TStringList* html=new TStringList();
html->LoadFromFile("D:\\1.htm");
regex expression("\\s+width=([^\"]*)\s+",regbase::normal|regbase::icase);
DWORD start=GetTickCount();
for(int n=0;n<html->Count;n++)
{
string s=html->Strings[n].c_str();
deque<string> result;
regex_split(std::back_inserter(result),s,expression);
copy(result.begin(),result.end(),ostream_iterator<string>(cout,"\n"));
result.clear();
}
start=GetTickCount()-start;
delete html;
cout<<start;
int c;
cin>>c;
return 0;
}
输出结果为671毫秒,拆分得到1072个width属性值,我们可以看到boost的效率是非常高的,虽然与一些角本语言比起来解析速度还是慢,但已经可以满足大多数编程要求了。另外作者的计算机配置并不是非常高,相信拿到现在任何一台主流配置的计算机上都会优于作者的结果。
结束语
其实上面的强大威力只是boost的冰山一角,如果你不自己去体会,你很难想象到boost的强大威力。在boost里还有很多使用的库,比如格式化输出,字符串拆解,类型转换等,这些库使用起来也比较方便,大家可以自行参考boost文档。在这些库中还有两个库需要自行编译,他们是Python和thread库,而且这些库的编译需要专门的工具Jam,所以我们在编译这些库的时候还要编译jam工具,而编译jam工具也不是一件快乐的事情,麻烦同样出现在如果你安装了多个编译器,如果读者有兴趣可以自己试一下。
不过BCB6并不支持全部boost库,从boost提供的编译器支持表可以看到[2],BCB6还是有相当多的库不支持的,支持最好的是gcc/g++的编译器,但也不是全部支持。希望borland下一个将要发布的C++编译器可以支持更多C++标准。
--------------------------------------------------------------------------------
[1] 其实还有其他类型的包,但在windows系统下,你最好下载zip包
[2] Boost提供的编译器支持表是针对BCB5的,对于BCB6的支持作者并没有详细测试,如果读者有兴趣可以自己测试boost附带的测试代码。
Boost是一个基于Template的开发源代码库,在这个库中有很多子库用来高效处理各方面的问题,比如字符串拆分,格式化,线程等等,Boost对于每一个C++爱好者都是应该了解的,对于C++ Builder用户如果能在熟练使用VCL的情况下再熟练使用Boost,我想一定如虎添翼。
一般来说,使用Boost是非常简单,和使用其他STL库没有太大区别,但使用Boost的正则表达式库则不那么容易,因为这个库还需要我们单独编译,下面我将详细介绍如何使用。
如果你还不知道或者还没有Boost的话,你可以去www.boost.org下载最新版本,作者使用的是1.30版本。将下载下来的zip包[1]解压到任何你喜欢的目录,比如D:\boost。
编译正则表达式库
前面已经提到,这个库需要我们单独编译才能使用,为什么不编译好一起发布呢?主要是考虑到不同的编译器需要不同的链接库文件和链接库太大了。在命令行下,进入[%Boost]\Libs\RegEx\Build目录,直接敲入make –fbcb6.bat命令开始编译,这里请大家注意了,如果你的计算机上同时安装了BCB5,请一定要把path设置成为BCB6的bcc32.exe程序所在的目录,否则可能使用BCB5的make程序,这样虽然能编译但最后不能使用。
编译过程相当耗时,你需要耐心等待,最终编译完成,会在[%Boost]\Libs\RegEx\Build目录生成一个BCB6目录,在这个目录生成了很多lib文件和dll文件,把所有dll文件复制到windows系统目录,所以lib文件复制到bcb6\lib目录。如果你不想这么麻烦的复制文件,可以在编译时加入install参数,就像这样make –fBcb6.bat install,不过作者还是比较喜欢前一种方式,这样我可以知道到底生成了什么文件。现在编译已经完成了,你可以体现boost的神奇魅力了。
一个测试程序
在BCB6中创建console程序,编写下列代码:
#include<deque>
#include<iostream>
#include<algorithm>
#include<boost/regex.hpp>
int main()
{
using namespace boost;
using namespace std;
regex expression("\\s+href\\s*=\\s*\"([^\"]*)\"",regbase::normal|regbase::icase);
string s="<a href=\"index.html\"><img src=\"logo.gif\"></a>";
deque<string> result;
regex_split(std::back_inserter(result),s,expression);
copy(result.begin(),result.end(),ostream_iterator<string>(cout,"\n"));
int c;
cin>>c;
return 0;
}
设置BCB6 Project属性的Lib Path和Include Path为你安装boost的目录,运行你会看到结果:
index.html
可以看到index.html已经从字符串中提出出来了,那么为什么会是这样呢?
代码的核心部分是:
regex expression("\\s+href\\s*=\\s*\"([^\"]*)\"",regbase::normal|regbase::icase);
它用来设置如何匹配字符串,上面乱七八糟的字符串很难看懂,如果不了解正则表达式的书写规则,上面代码可以和天书媲美。
regbase::normal|regbase::icase 是解析参数设置,具体可以参考boost帮助文档。
正则表达式的书写规则
具体的书写规则,大家可以参看boost的文档,我这里做一下简要说明:
. (dot)
用来匹配任何一个字符,但不包括新行上的字符
*
闭包,任意有限次的自重复连接
+
有限次自重复连接,但至少出现一次
{}
指定可能的重复次数
例如:
ba* 匹配 b ba baa baaa等
ba+ 匹配 ba baa baaaaaaaaa等
ba{1,5} 匹配 ba baa baaa baaaa baaaaa
\
转义字符,有很多用途,根据参数设置而变化,最常见的就是类似于c语言\的用法
\s
匹配空格
\w
匹配一个单词
\d
匹配数字
()
有两种用法:
1是合并的作用,例如(ab)*匹配ab abab ababab等
2是确定匹配,也就是说在()中的字符将被最终拆解出来
根据上面这张表,我们可以很容易知道前面的那段天书如何解释。
一个实际的例子
前一段时间在CSDN上有一篇帖子,问题是有一种文件结构如(类似):
@People{
Age=19
Speek=”Hay,{name},how are you”
}
问如何拆分字符串得到@后面的名字,=两边的属性名和属性值,引号里{}种的名字。
解决这个问题用正则表达式再合适不过了。
根据分析,我们可以这样构造匹配规则:
"@(.*?)\s*\\{" 匹配@开始的字符创,后面两种类型如何构造匹配规则留给大家思考吧。
这样我们可以轻易拆解这个例子。
性能分析
通过上面的讨论,大家已经了解到boost的强大威力,那个性能又如何呢?为此我们再实际来拆分一个复杂的html代码,看看到底需要花费多少时间。
为了节省篇幅,这里就不列出html代码了,不过可以告诉大家,这是一个又Word生成的大小为186K的html文件,这个文件中用到了很多<table>标签,所以我这里测试就来拆分所有<table>标签的width属性。测试代码如下:
#include<deque>
#include<iostream>
#include<algorithm>
#include<boost/regex.hpp>
#include<vcl.h>
int main()
{
using namespace boost;
using namespace std;
TStringList* html=new TStringList();
html->LoadFromFile("D:\\1.htm");
regex expression("\\s+width=([^\"]*)\s+",regbase::normal|regbase::icase);
DWORD start=GetTickCount();
for(int n=0;n<html->Count;n++)
{
string s=html->Strings[n].c_str();
deque<string> result;
regex_split(std::back_inserter(result),s,expression);
copy(result.begin(),result.end(),ostream_iterator<string>(cout,"\n"));
result.clear();
}
start=GetTickCount()-start;
delete html;
cout<<start;
int c;
cin>>c;
return 0;
}
输出结果为671毫秒,拆分得到1072个width属性值,我们可以看到boost的效率是非常高的,虽然与一些角本语言比起来解析速度还是慢,但已经可以满足大多数编程要求了。另外作者的计算机配置并不是非常高,相信拿到现在任何一台主流配置的计算机上都会优于作者的结果。
结束语
其实上面的强大威力只是boost的冰山一角,如果你不自己去体会,你很难想象到boost的强大威力。在boost里还有很多使用的库,比如格式化输出,字符串拆解,类型转换等,这些库使用起来也比较方便,大家可以自行参考boost文档。在这些库中还有两个库需要自行编译,他们是Python和thread库,而且这些库的编译需要专门的工具Jam,所以我们在编译这些库的时候还要编译jam工具,而编译jam工具也不是一件快乐的事情,麻烦同样出现在如果你安装了多个编译器,如果读者有兴趣可以自己试一下。
不过BCB6并不支持全部boost库,从boost提供的编译器支持表可以看到[2],BCB6还是有相当多的库不支持的,支持最好的是gcc/g++的编译器,但也不是全部支持。希望borland下一个将要发布的C++编译器可以支持更多C++标准。
--------------------------------------------------------------------------------
[1] 其实还有其他类型的包,但在windows系统下,你最好下载zip包
[2] Boost提供的编译器支持表是针对BCB5的,对于BCB6的支持作者并没有详细测试,如果读者有兴趣可以自己测试boost附带的测试代码。
最新更新
Objective-C语法之代码块(block)的使用
VB.NET eBook
Add-in and Automation Development In VB.NET 2003 (F
Add-in and Automation Development In VB.NET 2003 (8
Add-in and Automation Development in VB.NET 2003 (6
Add-in and Automation Development In VB.NET 2003 (5
AddIn Automation Development In VB.NET 2003 (4)
AddIn And Automation Development In VB.NET 2003 (2)
Addin and Automation Development In VB.NET 2003 (3)
AddIn And Automation Development In VB.NET 2003 (1)
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
武装你的WEBAPI-OData入门
武装你的WEBAPI-OData便捷查询
武装你的WEBAPI-OData分页查询
武装你的WEBAPI-OData资源更新Delta
5. 武装你的WEBAPI-OData使用Endpoint 05-09
武装你的WEBAPI-OData之API版本管理
武装你的WEBAPI-OData常见问题
武装你的WEBAPI-OData聚合查询
OData WebAPI实践-OData与EDM
OData WebAPI实践-Non-EDM模式