• 微信号
  • 微信号
您当前的位置:首页 > 学海无涯 > 茑语花香>C/C++中正则表达式库RE2的使用

C/C++中正则表达式库RE2的使用

猪猪侠 i语言 2023-07-28 1人阅读
RE2是Google开源的正则表达式库,RE2是多语言支持的,提供对C/C++,Python,Ruby等,本文介绍C语言的RE2的正则库。正则表达式在工程实践中是非常有用的,可用于信息提取,内容比对,替换等。 
安装 
主要步骤,下载安装包[GitHub地址],解压,编译,安装。需要说明的是较新版本源码添加了对C++11的支持,同时也需要较高版本g++的支持,本文选择tag为re2-2016-02-01的较低版本。 
类简介 
使用RE2首先要构造正则表达式对象,RE2的构造函数如下: 
RE2(const StringPiece& pattern); 
RE2(const StringPiece& pattern, const Options& option); 

其中StringPiece是RE2提供的一个string风格的对象,在RE2构造函数中传入”const char*” 或者”string”对象时,将被隐式的转换为StringPiece对象。使用StringPiece可以减少”const char*”到”string”之间的来来回回的转换。StringPiece包含一个指向原始输入的指针,和一个字符串的长度计数,构造函数如下:

class StringPiece { 
private: 
const char* ptr_; 
int length_; 

public: 

StringPiece() : ptr_(NULL), length_(0) { } 
StringPiece(const char* str): ptr_(str), length_((str == NULL) ? 0 : static_cast<int>(strlen(str))) { } 
StringPiece(const std::string& str): ptr_(str.data()), length_(static_cast<int>(str.size())) { } 
StringPiece(const char* offset, int len) : ptr_(offset), length_(len) { } 
... 
};

Options:构造函数中的Options,用于改变默认的设置,它是一个枚举类型,枚举值为:

DefaultOptions ,默认 
Latin1, //将输入当做Latin-1(ISO-8859-1)编码,默认为UTF-8 
POSIX, // POSIX语法,即从左开始最长匹配 
Quiet // 不要输出正则表达式编译的错误等 

RE2类的其他方法:

//返回RE2对象是否被正确的创建 
bool ok() const { return error_code() == NoError; } 
//如果RE2对象没有被正确的创建,将返回相关的错误描述 
const string& error() const { return *error_; } 

使用
下面介绍使用正则表达式提取结果的方法
1.Extract

/* 
*用于从text内容中,根据正则表达式提取内容 
*text:待提取的内容 
*pattern:构造,编译后的正则表达式 
*rewrite:控制输出结果 
*out:按照rewrite定义的输出结构 
*/ 
static bool Extract(const StringPiece &text, const RE2& pattern, const StringPiece &rewrite, string *out); 
text:待提取的内容 
pattern:构造,编译后的正则表达式 
rewrite:控制输出结果 
out:按照rewrite定义的输出结构

这里重点说下rewrite,它用于控制输出结果,如果正则表达式含有多个字表达式,那么rewrite可以控制输出哪些匹配结果,它通常是’[digits]’,其中\0表示完整的匹配结果,而\1则表示第一个字表达式。例如:表达式regmail中含有多个字表达式,下面分别用\1,\3,\5分别输出邮箱的用户名,用户名等。

string content = "test,regular,邮件 test@gmail.com;"; 
string regmail = "(\\w+([-+.]\\w+)*)@(\\w+([-.]\\w+)*)\\.(\\w+([-.]\\w+)*)"; 
re2::RE2::Extract(content.c_str(),*pHandle,"\\0,\\1,\\3,\\5",&strVal); 
strVal的值为"test@gmail.com,test,gmail,com" //分隔符','是在rewrite中定义的符号

2.Match

bool Match(const StringPiece& text,int startpos, int endpos, Anchor anchor, StringPiece *match, int nmatch) const; 
text:待匹配的文本 
startpos:从text中进行匹配的开始位置 
endpos:从text中进行匹配的结束位置 
anchor:匹配的模式,Anchor是一个枚举类型,其值分别为:UNANCHORED表示从startpos到endpos之间任何位置开始匹配,ANCHOR_START表示只能从startpos开始匹配, ANCHOR_BOTH表示模式必须完全匹配startpos到endpos之间的字符串。 
match:它通常是是一个StringPiece数组,用于保存匹配结果 
nmatch:匹配的字段个数,通常nmatch值越小,匹配速度越快,应该避免使得nmatch>1+match数组的长度

下面介绍Anchor类型对匹配结果的影响:

StringPiece group[3]; 
RE2 re("(\\w+):([0-9]+)"); 
string content = "please visit 127.0.0.1:8999 here"; 
if(re.Match(content,0,content.size(),RE2::UNANCHORED,group,3)) 
{ 
for(size_t i = 0; i < 3 ;++i) 
{ 
cout<<group<<";"; 
} 
cout<<endl; 
}

上述的正则表达式包含两个子表达式,group[0]是完整的匹配结果,group[1],group[2]分别输出模式”(\w+)”和”([0-9]+)”的结果,其输出如下:localhost:8999;localhost;8999;
如果将匹配模式改为:

re.Match(content,0,content.size(),RE2::ANCHOR_START,group,3); 

那么只能匹配content值为”127.0.0.1:8999 here”,ANCHOR_START指明模式必须从startpos就开始匹配。
而如果将匹配模式改为:

re.Match(content,0,content.size(),RE2::ANCHOR_BOTH,group,3); 

那么只能匹配content值为”127.0.0.1:8999”,ANCHOR_BOTH指明模式必须从startpos到endpos之间完全匹配。
3.FullMatch

static bool FullMatchN(const StringPiece& text, const RE2& re,const Arg* const args[], int argc); 
static const VariadicFunction2<bool, const StringPiece&, const RE2&, Arg, RE2::FullMatchN> FullMatch; 

FullMatch通过模板VariadicFunction2,支持可变参数,将要提取的表达式,通过FullMatchN函数实现。使用:

string content = "please visit localhost:8999 here"; 
string host; 
int port; 
RE2::FullMatch("local:8999","(\\w+):([0-9]+)",&host,&port); 

匹配模式中含有两个子表达式,其值分别通过变量host和port进行提取。使用RE2::FullMatch(“local:8999”,”(\w+):([0-9]+)”,&host,&port);形式调用FullMatch,每次调用的时编译一次正则表达式,如果多次使用同一个匹配模式,这样会造成很多不必要的开销。可以编译一次正则表达式,保存到一个RE2对象中,然后在每次调用时重用这个对象。如:

RE2 re("(\\w+):([0-9]+)"); 
RE2::FullMatch("master:8088", re, &host, &port);

4.Replace & GlobalReplace

static bool Replace(string *str, const RE2& pattern, const StringPiece& rewrite); 
static int GlobalReplace(string *str, const RE2& pattern, const StringPiece& rewrite); 
str:待替换的原始字符串,注意这一个指针,所有如果有匹配结果,将会直接修改原始数据; 
pattern:匹配的模式,即正则表达式 
rewrite:替换的模式,可以带有'\[digits]'表示的子模式结果

两者都可以用于替换,区别在于前只替换第一个匹配的结果,后者则会匹配所有匹配结果。关于返回值:前者返回是否替换成功(最多只会替换一次),后者返回全局整体被成功替换的次数。如下:

RE2 re("(\\w+):([0-9]+)"); 
string content = "please visit localhost:8999 master:8088 here"; 
if(RE2::Replace(&content, re, "127.0.0.1:\\2")) 
{ 
cout<<content<<endl; //"please visit 127.0.0.1:8999 master:8088 here" 只有第一个匹配结果被替换 
} 
content = "please visit localhost:8999 or master:8088 here"; 
cout<<"relapce count:"<<RE2::GlobalReplace(&content, re, "127.0.0.1:\\2")<<endl; //"2",即有两处被替换 
out<<content<<endl; //"please visit 127.0.0.1:8999 or 127.0.0.1:8088 here"所有匹配结果都被替换

Demo

// g++ -g testRE2.cpp -o run -lre2 
#include <iostream> 
#include <string> 
#include "re2/re2.h" 

using namespace std; 
using namespace re2; 

int main() 
{ 
{ 
string regmail = "(\\w+([-+.]\\w+)*)@(\\w+([-.]\\w+)*)\\.(\\w+([-.]\\w+)*)"; 
RE2 *pHandle = NULL; 
pHandle = new RE2(regmail, re2::RE2::Quiet); 
if( !pHandle->ok() ) 
{ 
cout<<pHandle->error()<<endl; 
return -1; 
} 

string content = "test,regular,邮件 test@gmail.com; "; 
string strVal ; 
if(re2::RE2::Extract(content.c_str(),*pHandle,"\\0,\\1,\\3,\\5",&strVal)) 
{ 
cout<<strVal<<endl; 
} 
if(pHandle != NULL) 
{ 
delete pHandle; 
pHandle = NULL; 
} 
} 
{ 
StringPiece group[3]; 
RE2 re("(\\w+):([0-9]+)"); 
string content = "please visit localhost:8999 here"; 
if(re.Match(content,0,content.size(),RE2::UNANCHORED,group,3)) 
{ 
for(size_t i = 0; i < 3 ;++i) 
{ 
cout<<group<<";"; 
} 
cout<<endl; 
} 
} 
{ 
string host; 
int port; 
string content = "please visit localhost:8999 here"; 
RE2::FullMatch("localhost:8999","(\\w+):([0-9]+)",&host,&port); 
cout<<host<<":"<<port<<endl; 
RE2 re("(\\w+):([0-9]+)"); 
RE2::FullMatch("master:8088", re, &host, &port); 
cout<<host<<":"<<port<<endl; 
} 
{ 
RE2 re("(\\w+):([0-9]+)"); 
string content = "please visit localhost:8999 here"; 
if(RE2::Replace(&content, re, "127.0.0.1")) 
{ 
cout<<content<<endl; 
} 
content = "please visit localhost:8999 or master:8088 here"; 
cout<<"relapce count:"<<GlobalReplace(&content, re, "127.0.0.1")<<endl; 
cout<<content<<endl; 
} 
return 0; 
}

本文简介了使用C/C++语言操作RE2库的主要方法,至于正则表达式的语法详见RE2的参考文档。

转载:感谢您阅览,转载请注明文章出处“来源从小爱孤峰知识网:一个分享知识和生活随笔记录的知识小站”。

链接:C/C++中正则表达式库RE2的使用http://www.gufeng7.com/niaolang/1796.html

联系:如果侵犯了你的权益请来信告知我们删除。邮箱:119882116@qq.com

标签: