什么是正則表達式?正則表達式是一種用來描述一定數量文本的模式。Regex代表Regular Express。
如果您不知道什么是正則表達式,請看這篇文章http://blog.csdn.net/begtostudy/archive/2007/11/11/1879206.aspx
有了正則表達式的基礎,問題是如何使用。我們以boost::regex來說
先看一個網上經典的例子。
#include "stdafx.h"
#include <cstdlib>
#include <stdlib.h>
#include <boost/regex.hpp>
#include <string>
#include <iostream>
using namespace std;
using namespace boost;
regex expression("^select ([a-zA-Z]*) from ([a-zA-Z]*)");
int main(int argc, char* argv[])
{
std::string in;
cmatch what;
cout << "enter test string" << endl;
getline(cin,in);
if(regex_match(in.c_str(), what, expression))
{
for(int i=0;i<what.size();i++)
cout<<"str :"<<what[i].str()<<endl;
}
else
{
cout<<"Error Input"<<endl;
}
return 0;
}
==============
結果
輸入:select name from table
輸出:str:select name from table
str:name
str:table
按照我們的要求,字符串被匹配挑出來了。
這在處理大量規則的文本格式的時候很有用,因為它很靈活,一通百通。
首先,即使你擁有了boost庫,也需要單獨編譯regex。
如果你不知道boost庫,看這里http://www.stlchina.org/twiki/bin/view.pl/Main/BoostStartIntroduce
網上的介紹:
boost庫安裝比較麻煩,需要自己編譯源文件,我整理了一下,如果僅僅需要做正則表達式,按下面的代碼敲就行了:
cmd
vcvars32.bat
cd D:\boost_1_32_0\libs\regex\build
d:
nmake -fvc6.mak
nmake -fvc6.mak install
注意,別看下載下來的數據包沒有多大,解壓縮之后達到了100多M,編譯完之后為109M,占用131M,所以安裝時一定注意空出足夠的空間,敲入nmake -fvc6.mak后等待的時間比較長,屏幕上還會出現一大堆英語,可以不做考慮。按照步驟往下敲就行了。壓縮包內文檔很詳細,參照文檔繼續就可以了。
在VC6中集成:Tools->Options->Directories->Include files
加入:D:\boost_1_32_0
我用的是VS2003
做了run.bat
chdir E:\Program\boost_1_34_1
bjam "-sTOOLS=vc-7_1" "-sVC71_ROOT=D:\Program Files\Microsoft Visual Studio .NET 2003\Vc7" "--prefix=E:\Program\boost" "--builddir=E:\Program\boost_1_34_1\build" "-sBUILD=debug release <runtime-link>static/dynamic" --with-regex install
PAUSE
至於參數,需要參考boost安裝介紹http://blog.csdn.net/begtostudy/archive/2007/11/11/1879213.aspx
其他的一些介紹
bool validate_card_format(const std::string s)
{
static const boost::regex e("(\\d{4}[- ]){3}\\d{4}");
return regex_match(s, e);
}
boost::regex的默認正則表達式語法是perl語法
boost::regex支持perl regular表達式、POSIX-Extended regular表達式和POSIX-Basic Regular表達式,但默認的表達式語法是perl語法,如果要使用其余兩種語法需要在構造表達式的時候明確指定。
例如,下面兩種方法效果相同
// e1 is a case sensitive Perl regular expression:
// since Perl is the default option there''s no need to explicitly specify the syntax used here:
boost::regex e1(my_expression);
// e2 a case insensitive Perl regular expression:
boost::regex e2(my_expression, boost::regex::perl|boost::regex::icase);
perl正則表達式語法
perl正則表達式語法可參見《perl語言入門》第7、8、9章或boost的文檔。這里列出的語法是不全面的,而且部分說明可能並不清楚。
. 任意字符;使用match_no_dot_null標志時不匹配NULL字符; 使用match_not_dot_newline時不匹配換行字符
^ 匹配行的開始
$ 匹配行的結束
* 重復零次或則更多,例如a*b可匹配b,ab,aab,aaaaaaab
+ 重復一次以上,例如a+b可匹配ab,aab,aaaaaaaab。但不能匹配b了
? 零次或則一次,例如ca?b匹配cb,cab但不匹被caab
a{n} 匹配字符''a''重復n次
a{n,},字符a重復n次以上(含n次)
a{n,m} a重復n到m次(含)
*? 匹配前一個原子零次以上
+? 匹配前一個原子一次以上
?? 匹配前一個原子零次以上
{n,}? 匹配前一個原子n次以上(含)
{n,m? 匹配前一個原子n到m次(含)
| 或操作,例如ab(d|ef)匹配abd或則abef
[] 字符集操作,例如[abc]將匹配任何單個字符''a'',''b'',''c''
[a-d],表示a、b、c、d
^否操作,例如[^a-c]表示a至c之外的所有字符
boost::regex對unicode編碼的支持
boost::regex使用ICU來實現對unicode及unicode變種的支持,這需要在編譯boost的時候指出是否使用ICU以及ICU所在的目錄。否則編譯出來的boost::regex不支持unicode編碼。其中boost::wregex支持unicode編碼的搜索,如果要搜索UTF-8、UTF-16、UFT-32編碼的字符串,則要用boost::u32regex。注意boost::wregex只能支持unicode編碼,不能支持uft編碼。
搜索時如何忽略大小寫
如果要在搜索時忽略大小寫(即大小寫不敏感),則要用到表達式選項boost::regex::icase,例如: boost::regex e2(my_expression, boost::regex::perl|boost::regex::icase);
模板類:
l basic_regex 用來保存一個“正則表達式”的類。
l sub_match 繼承於pair<Iterator,Iterator>迭代器組,用來表示匹配的一個結果。
l match_results sub_match的容器,用來表示一次搜索或匹配算法的所有結果,類似於vector<sub_match>。
算法:
l regex_math 匹配算法,測試一個字符串是否和一個正則式匹配,並通過match_results返回結果。
l regex_find 查找算法,查找字符串的一個和正則式匹配的字串,並通過match_results返回結果。
l regex_format 替換算法,查找字符串中的所有匹配正則式的字串,並使用“格式化字符”串替換。
迭代器:
l regex_iterator 枚舉一個字符串中所有匹配的字串,regex_iterator的結果相當於match_results。
l regex_token_iterator 枚舉一個字符串中所有匹配的字串,regex_iterator的結果相當於sub_match。
詳述
l basic_regex
template <class charT, class traits = regex_traits<charT>, class Allocator = std::allocator<charT> >
class basic_regex;
typedef basic_regex<char> regex;
typedef basic_regex<wchar_t> wregex;
很明顯,charT是正則式的字符類型,regex和wregex是basic_regex的兩個特化。
注意,正則式的字符類型要和需要匹配的字符串的字符類型相同。例如:不能在regex_find算法中分別使用string和wregex最為參數,要么是string和regex,要么是wstring和wregex。
構造函數:
basic_regex re |
產生空的正則式 |
basic_regex re(str) |
正則式為str,str可以為basic_string,也可以是0結尾的char*字符串。 |
Basic_regex re(re2) |
拷貝構造。 |
basic_regex re(str,flag) |
正則式為str,使用flag語法選項,flag是一組常量的組合。例如:icase可以使正則式匹配忽略大小寫。 |
basic_regex re(beg,end) |
使用迭代器構造正則式。可以是basic_string的迭代器,也可以是const char*。 |
basic_regex re(beg,end,flag) |
使用迭代器構造正則式,flag是語法選項。 |
常用的語法選項:
regex_constants::normal |
默認的語法。符合EMCAScript,JavaScript中的正則式。 |
regex_constants::icase |
匹配的時候忽略大小寫。 |
regex_constants::nosubs |
不把匹配的子串保存進match_results結構。 |
regex_constants::collate |
對於[a-b]的匹配,考慮地區 |
語法選項通過或運算來結合。在basic_regex中這些語法選項也進行了定義,所以可以寫成regex::normal,這要比regex_constants少打好幾個字母了吧!J
assign成員函數:
re.assign(re2) |
復制一個正則式 |
re.assign(str) |
正則式為str。 |
re.assign(str, flag) |
正則式為str,使用flag語法選項,flag是一組常量的組合。 |
re.assign(beg, end) |
使用迭代器構造正則式。 |
re.assign(beg, end, flag) |
使用迭代器構造正則式,flag是語法選項。 |
其實basic_regex很多用法和basic_string很像,因為正則表達式也是個字符串嘛!
迭代器:
regex::iterator it |
常迭代器類型,即const_iterator |
re.begin() |
返回的是常迭代器哦!const_iterator |
re.end() |
沒有逆向迭代器。 |
例如:copy(re.begin(), re.end(), ostream_iterator<char>(cout));
其他:
re.size() |
正則表達式長度,即str的長度。 |
re.max_size() |
正則表達式的最大長度。 |
re.empty() |
長度是否為0 |
re.mark_count() |
返回正則式的組數,一般情況下為小括號對數+1。在boost.regex中使用小括號分組,詳情請看下面的算法詳解。 |
re.flags() |
返回語法選項。 |
cout<<re |
正則式的流輸出,相當於上面示例的copy算法。 |
swap |
成員函數,全局函數都有 |
re.imbue(loc) |
設置local為loc,返回原來的local |
re.getloc() |
得到當前local |
==,!=,<,<=,>,>= |
比較運算符重載 |
l sub_match
sub_match是一個迭代器組,表示正則式中的一個匹配。
template <class BidirectionalIterator>
class sub_match : public std::pair<BidirectionalIterator, BidirectionalIterator>;
boost沒有提供sub_match的任何特化,因為我們不會顯示的聲明一個sub_match變量。sub_match是作為match_results的元素用的。比如:match_results的operator[]和迭代器返回的就是一個特化的sub_match。
唯一的成員變量:
bool matched 是否匹配。
成員函數:
length() |
返回長度,即兩個迭代器之間的距離。 |
operator basic_string< value_type>() |
隱式的basic_string轉換。 |
str() |
顯式的basic_string轉換。 |
還有就是一大堆的比較操作符的重載了,這里就不多說了。
l match_results
match_results相當於sub_match的容器,用於表示正則式算法的返回結果。
template <class BidirectionalIterator,
class Allocator = allocator<sub_match<BidirectionalIterator> >
class match_results;
typedef match_results<const char*> cmatch;
typedef match_results<const wchar_t*> wcmatch;
typedef match_results<string::const_iterator> smatch;
typedef match_results<wstring::const_iterator> wsmatch;
聲明很簡單,有四個特化可以直接使用,不過要注意string和char*字符串使用的match_results是不同的。
成員函數:
m.size() |
容量。 |
m.max_size() |
最大容量。 |
m.empty() |
容量是否為0。 |
m[n] |
第n個元素,即sub_match |
m.prefix() |
返回代表前綴的sub_match,前綴指字符串的開頭到第一個匹配的開頭。 |
m.suffix() |
返回代表后綴的sub_match,后綴之最后一個匹配的結尾到字符串的結尾。 |
m.length(n) |
返回第n個元素的長度,即m[n].size()。 |
m.position(n) |
返回第n個元素的位置。 |
cout<<m |
流輸出,輸出整個匹配,相當於cout<<m[0]。因為第0個元素是整個匹配,詳細情況請看下面的解釋。 |
m.format(fmtstr) |
使用格式化字符串,格式化結果,返回字符串 |
m.format(fmtstr,flags) |
使用格式化字符串,格式化結果,返回字符串,flags是格式化選項。 |
m.format(out,fmtstr) |
同上,但是使用輸出迭代器輸出結果。 |
m.format(out.fmtstr,flags) |
同上,但是使用輸出迭代器輸出結果。 |
迭代器:
smatch::iterator |
迭代器,常迭代器 |
smatch::const_iterator |
同上 |
m.begin() |
返回常迭代器 |
m.end() |
同上 |
最后,說一個實例
我處理一個文本
實際值/-20.031,-1.896,-2.861,-1,0,0
提取其中的數字
regex exp("\s*實際值/(-?[0-9.]+),(-?[0-9.]+),(-?[0-9.]+),(-?[0-9.]+),(-?[0-9.]+),(-?[0-9.]+)$");
大家看看還有沒有更好的寫法?
regex_match
regex_match算法用來測試一個字符串是否完全匹配正則式。讓我們來看一下regex_match的使用:
if (regex_match(str, m, re))
{
...
}
str是一個字符串,可以是string,wstring,char *或者wchar_t *
m是match_results,它通過引用傳入參數,來保存匹配的結果,m要和str的類型匹配,可以是smatch,wsmatch,cmatch或wcmatch,用來分別對應string,wstring,char *或者wchar_t*的str。
re就是正則表達式了,一般來說是regex或wregex。
str,m,re的類型如下:
str類型 |
m類型 |
re類型 |
string |
smatch (match_results<string::const_iterator>) |
regex (basic_regex<char>) |
wstring |
wsmatch (match_results<wstring::const_iterator>) |
wregex (basic_regex<wchar_t>) |
char* |
cmatch (match_results<const char*>) |
regex (basic_regex<char>) |
wchar_t* |
wcmatch (match_results<const wchar_t*>) |
wregex (basic_regex<wchar_t>) |
函數的返回值表示字符串是否完全匹配正則表達式,當返回true的時候,m保存了匹配的結果;返回false,m未定義。
下面讓我們來看一下,當函數返回true的時候,m是怎么樣的。
m.size() == re.mark_count()
還記得re.mark_count()返回的是什么嗎?在上一篇中說的是re.mark_count()返回的時正則式的“組數”,並沒有詳細解釋。這里我要詳細解釋一下。
其實,這個“組數”在boost的regex中叫做sub-expression。sub-expression就是在正則式中使用小括號括起來的一部分,正則式本身是一個sub-expression,所以re.mark_count()等於小括號對數+1。
m.prefix()和m.suffix()
這兩個返回的是sub_match類型(相當於一個迭代器組)。在regex_match算法中,這兩個返回的sub_match都是空的,他們的值如下:(sub_match繼承於pair,所以有first和second成員哦)
m.prefix().first == str.begin()
m.prefix().second == str.begin()
m.prefix().matched == false
m.suffix().first == str.end()
m.suffix().second == str.end()
m.suffix().matched == false
因為regex_match是完全匹配,即整個字符串和正則式匹配,所以前綴和后綴都是空的。
m[0]
返回第0個匹配的,由於regex_match是完全匹配,所以
m[0].first == str.begin()
m[0].second == str.end()
m[0].matched == true
m[n] , n<m.size()
返回第n個匹配的sub-expression。
m[n].matched 表示第n個sub-expression是否在字符串中存在。整個regex匹配,但是sub_exp可能匹配的是空的,例如”(a*)”就有可以匹配空。
m[n].first和m[n].second 表示匹配的范圍。如果匹配空的話,都為str.end()。
根據我的測試,m[1],m[2],...,m[n]的順序是按照正則式的左小括號的順序來的,例如對於正則式”((a)bc)d(efg)”,如果匹配了一個字符串的話(字符串只可能是”abcdefg”),則
m[0] == “abcdefg” (sub_match重載了==運算符使得可以和一個字符串比較)
m[1] == “abc”
m[2] == “a”
m[3] == “efg”
regex_match的其它用法
regex_match(str,re) |
只測試是否匹配,不需要匹配的結果 |
regex_match(beg,end,re) |
輸入的是迭代器 |
regex_match(beg,end,m,re) |
注意m的類型為match_results<iterator> |
regex_match(str,m,re,flag) |
flag是匹配選項,默認是的regex_constants::match_default |
regex_search
regex_search的用法基本上和regex_match一樣。
if (regex_search(str, m, re))
{
...
}
regex_search不要求str完全匹配re,只要str中的一個字串匹配re就可以了。所以,m.prefix()和m.suffix()不一定為空。
regex_search是從左往右匹配,而且盡量匹配長的字串。