Boost::Regex

boost.regex正则表达式 boost::regex正则表达式 阅读详情
 要使用Boost.Regex, 你需要包含头文件 "boost/regex.hpp". Regex是本书中两个需要独立编译的库之一(另一个是Boost.Signals)。你会很高兴获知如果你已经构建了Boost— —那只需在命令提示符下打一行命令——就可以自动链接了(对于Windows下的编译器),所以你不需要为指出那些库文件要用而费心。

你要做的第一件事就是声明一个类型 basic_regex 的变量。这是该库的核心类之一,也是存放正则表达式的地方。创建这样一个变量很简单;只要将一个含有你要用的正则表达式的字符串传递给构造函数就行了。

boost::regex reg("(A.*)");

这个正则表达式具有三个有趣的特性。第一个是,用圆括号把一个子表达式括起来,这样可以稍后在同一个正则表达式中引用它,或者取出匹配它的文本。我们稍后会详细讨论它,所以如果你还不知道它有什么用也不必担心。第二个是,通配符(wildcard)字符,点。这个通配符在正则表达式中有非常特殊的意义;这可以匹配任意字符。最后一个是,这个表达式用到了一个重复符,*, 称为Kleene star, 表示它前面的表达式可以被匹配零次或多次。这个正则表达式已可以用于某个算法了,如下:

bool b=boost::regex_match(
"This expression could match from A and beyond.",
reg);

如你所见,你把正则表达式和要分析的字符串传递给算法 regex_match. 如果的确存在与正则表达式的匹配,则该函数调用返回结果 true ;否则,返回 false. 在这个例子中,结果是 false, 因为 regex_match 仅当整个输入数据被正则表达式成功匹配时才返回 true 。你知道为什么是这样吗?再看一下那个正则表达式。第一个字符是大写的 A, 很明显能够匹配这个表达式的第一个字符在哪。所以,输入的一部分"A and beyond."可以匹配这个表达式,但这不是整个输入。让我们试一下另一个输入字符串。

bool b=boost::regex_match(
"As this string starts with A, does it match? ",
reg);

这一次,regex_match 返回 true. 当正则表达式引擎匹配了 A, 它接着看后续有什么。在我们的regex变量中,A 后跟一个通配符和一个Kleene star, 这意味着任意字符可以被匹配任意次。因而,分析过程开始扔掉输入字符串的剩余部分,即匹配了输入的所有部分。

接下来,我们看看如何使用regexes 和 regex_match 来进行数据验证。

验证输入

正则表达式常用于对输入数据的格式进行验证。应用软件通常要求输入符合某种结构。考虑一个应用软件,它要求输入一定要符合如下格式,"3个数字, 一个单词, 任意字符, 2个数字或字符串"N/A," 一个空格, 然后重复第一个单词." 手工编写代码来验证这个输入既沉闷又容易出错,而且这些格式还很可能会改变;在你弄明白之前,可能就需要支持其它的格式,你精心编写的分析器可能就需要修改并重新调试。让我们写出一个可以验证这个输入的正则表达式。首先,我们需要一个匹配3个数字的表达式。对于数字,我们应该使用一个特别的缩写,/d。要表示它被重复3次,需要一个称为bounds operator的特定重复,它用花括号括起来。把这两个合起来,就是我们的正则表达式的开始部分了。

boost::regex reg("//d{3}");

注意,我们需要在转义字符(/)之前加一个转义字符,即在我们的字符串中,缩写 /d 变成了 //d 。这是因为编译器会把第一个/当成转义字符扔掉;我们需要对/进行转义,这样/才可以出现在我们的正则表达式中。

接下来,我们需要定义一个单词的方法,即定义一个字符序列,该序列结束于一个非字母字符。有不只一种方法可以实现它,我们将使用字符类别(也称为字符集)和范围这两个正则表达式的特性来做。字符类别即一个用方括号括起来的表达式。例如,一个匹配字符a, b, 和 c中任一个的字符类别表示为:[abc]. 如果用范围来表示同样的东西,我们要写:[a-c]. 要写一个包含所有字母的字符类型,我们可能会有点发疯,如果要把它写成: [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ], 但不用这样;我们可以用范围来表示:[a-zA-Z]. 要注意的是,象这样使用范围要依赖于当前所用的locale,如果正则表达式的 basic_regex::collate 标志被打开。使用以上工具以及重复符 +, 它表示前面的表达式可以重复,但至少重复一次,我们现在可以表示一个单词了。

boost::regex reg("[a-zA-Z]+");

以上正则表达式可以工作,但由于经常要表示一个单词,所以有一个更简单的方法:/w. 这个符号匹配所有单词,不仅是ASCII的单词,因此它不仅更短,而且也更适用于国际化的环境。接下来的字符是一个任意字符,我们已经知道要用点来表示。

boost::regex reg(".");

再接下来是 2个数字或字符串 "N/A." 为了匹配它,我们需要用到一个称为选择的特性。选择即是匹配两个或更多子表达式中的任意一个,每种选择之间用 | 分隔开。就象这样:

boost::regex reg("(//d{2}|N/A)");

注意,这个表达式被圆括号括了起来,以确保整个表达式被看作为两个选择。在正则表达式中增加一个空格是很简单的;用缩写/s. 把以上每一样东西合并起来,就得到了以下表达式:

boost::regex reg("//d{3}[a-zA-Z]+.(//d{2}|N/A)//s");

现在事情变得有点复杂了。我们需要某种方法,来验证接下来的输入数据中的单词是否匹配第一个单词(即那个我们用表达式[a-zA-Z]+所捕获的单词)。关键是要使用后向引用(back reference),即对前面的子表达式的引用。为了可以引用表达式 [a-zA-Z]+, 我们必须先把它用圆括号括起来。这使得表达式([a-zA-Z]+)成为我们的正则表达式中的第一个子表达式,我们就可以用索引1来建立一个后向引用了。

这样,我们就得到了整个正则表达式,用于表示"3个数字, 一个单词, 任意字符, 2个数字或字符串"N/A," 一个空格, 然后重复第一个单词.":

boost::regex reg("//d{3}([a-zA-Z]+).(//d{2}|N/A)//s//1");

干的好!下面是一个简单的程序,把这个表达式用于算法 regex_match, 验证两个输入字符串。

#include <iostream>
#include <cassert>
#include <string>
#include "boost/regex.hpp"

int main() {
// 3 digits, a word, any character, 2 digits or "N/A",
// a space, then the first word again
boost::regex reg("//d{3}([a-zA-Z]+).(//d{2}|N/A)//s//1");

std::string correct="123Hello N/A Hello";
std::string incorrect="123Hello 12 hello";

assert(boost::regex_match(correct,reg)==true);
assert(boost::regex_match(incorrect,reg)==false);
}

第一个字符串,123Hello N/A Hello, 是正确的;123 是3个数字,Hello 是一个后跟任意字符(一个空格)的单词, 然后是N/A和另一个空格,最后重复单词Hello 。第二个字符串是不正确的,因为单词 Hello 没有被严格重复。缺省情况下,正则表达式是大小写敏感的,因而反向引用不能匹配。

写出正则表达式的一个关键是成功地分解问题。看一下你刚才建立的最终的那个表达式,对于未经过训练的人来说它的确很难懂。但是,如果把这个表达式分解成小的部分,它就不太复杂了。

查找

现在我们来看一下另一个Boost.Regex算法, regex_search. 与 regex_match 不同的是,regex_search 不要求整个输入数据完全匹配,则仅要求部分数据可以匹配。作为说明,考虑一个程序员的问题,他可能在他的程序中有一至两次忘记了调用 delete 。虽然他知道这个简单的测试可能没什么意义,他还是决定计算一下new 和 delete出现的次数,看看数字是否符合。这个正则表达式很简单;我们有两个选择,new 和 delete.

boost::regex reg("(new)|(delete)");

有两个原因我们要把子表达式用括号括起来:一个是为了表明我们的选择是两个组。另一个原因是我们想在调用regex_search时引用这些子表达式,这样我们就可以判断是哪一个选择被匹配了。我们使用regex_search的一个重载,它接受一个match_results类型的参数。当 regex_search 执行匹配时,它通过一个match_results类型的对象报告匹配的子表达式。类模板 match_results 使用一个输入序列所用的迭代器类型来参数化。

template <class Iterator,
class Allocator=std::allocator<sub_match<Iterator> >
class match_results;

typedef match_results<const char*> cmatch;
typedef match_results<const wchar_t> wcmatch;
typedef match_results<std::string::const_iterator> smatch;
typedef match_results<std::wstring::const_iterator> wsmatch;

我们将使用 std::string, 所以要留意 typedef smatch, 它是 match_results<std::string::const_iterator>的缩写。如果 regex_search 返回 true, 传递给该函数的 match_results 引用将包含匹配的子表达式结果。在 match_results里,用已索引的sub_match来表示正则表达式中的每个子表达式。我们来看一下我们如何帮助这位困惑的程序员来计算对new 和 delete的调用。

boost::regex reg("(new)|(delete)");
boost::smatch m;
std::string s=
"Calls to new must be followed by delete. /
Calling simply new results in a leak!";

if (boost::regex_search(s,m,reg)) {
// Did new match?
if (m[1].matched)
std::cout << "The expression (new) matched!/n";
if (m[2].matched)
std::cout << "The expression (delete) matched!/n";
}

以上程序在输入字符串中查找 new 或 delete, 并报告哪一个先被找到。通过传递一个类型 smatch 的对象给 regex_search, 我们可以得知算法如何执行成功的细节。我们的表达式中有两个子表达式,因此我们可以通过match_results的索引1得到子表达式 new . 这样我们得到一个 sub_match实例,它有一个Boolean成员,matched, 告诉我们这个子表达式是否参与了匹配。因此,对于上例的输入,运行结果将输出"The expression (new) matched!/n". 现在,你还有一些工作要做。你需要继续把正则表达式应用于输入的剩余部分,为此,你要使用另外一个 regex_search的重载,它接受两个迭代器,指示出要查找的字符序列。因为 std::string 是一个容器,它提供了迭代器。现在,在每一次匹配时,你必须把指示范围起始点的迭代器更新为上一次匹配的结束点。最后,增加两个变量来记录 new 和 delete的次数。以下是完整的程序:

#include <iostream>
#include <string>
#include "boost/regex.hpp"

int main() {
// "new" and "delete" 出现的次数是否一样?
boost::regex reg("(new)|(delete)");
boost::smatch m;
std::string s=
"Calls to new must be followed by delete. /
Calling simply new results in a leak!";
int new_counter=0;
int delete_counter=0;
std::string::const_iterator it=s.begin();
std::string::const_iterator end=s.end();

while (boost::regex_search(it,end,m,reg)) {
// 是 new 还是 delete?
m[1].matched ? ++new_counter : ++delete_counter;
it=m[0].second;
}

if (new_counter!=delete_counter)
std::cout << "Leak detected!/n";
else
std::cout << "Seems ok.../n";
}

注意,这个程序总是把迭代器 it 设置为 m[0].second。match_results[0] 返回对匹配整个正则表达式的子匹配的引用,因此我们可以确认这个匹配的结束点就是下次运行regex_search的起始点。运行这个程序将输出"Leak detected!", 因为这里有两次 new, 而只有一次 delete. 当然,一个变量也可能在两个地方删除,还有可能调用 new[] 和 delete[], 等等。

现在,你应该已经对子表达式如何分组使用有了较好的了解。现在是时候进入到最后一个Boost.Regex算法,该算法用于执行替换工作。

替换

Regex算法家族中的第三个算法是 regex_replace. 顾名思义,它是用于执行文本替换的。它在整个输入数据中进行搜索,查找正则表达式的所有匹配。对于表达式的每一个匹配,该算法调用 match_results::format 并输入结果到一个传入函数的输出迭代器。

在本章的介绍部分,我给出了一个例子,将英式拼法的 colour 替换为美式拼法 color. 不使用正则表达式来进行这个拼写更改会非常乏味,也很容易出错。问题是可能存在不同的大小写,而且会有很多单词被影响,如colourize. 要正确地解决这个问题,我们需要把正则表达式分为三个子表达式。

boost::regex reg("(Colo)(u)(r)",
boost::regex::icase|boost::regex::perl);

我们将要去掉的字母u独立开,为了在所有匹配中可以很容易地删掉它。另外,注意到这个正则表达式是大小写无关的,我们要把格式标志 boost::regex::icase 传给 regex 的构造函数。你还要传递你想要设置的其它标志。设置标志时一个常见的错误就是忽略了regex缺省打开的那些标志,如果你没有设置这些标志,它们不会打开,你必须设置所有你要打开的标志。

调用 regex_replace时,我们要以参数方式提供一个格式化字符串。该格式化字符串决定如何进行替换。在这个格式化字符串中,你可以引用匹配的子表达式,这正是我们想要的。你想保留第一个和第三个匹配的子表达式,而去掉第二个(u)。表达式 $N表示匹配的子表达式, N 为子表达式索引。因此我们的格式化串应该是 "$1$3", 表示替换文本为第一个和第三个子表达式。通过引用匹配的子表达式,我们可以保留匹配文本中的所有大小写,而如果我们用字符串来作替换文本则不能做到这一点。以下是解决这个问题的完整程序。

#include <iostream>
#include <string>
#include "boost/regex.hpp"

int main() {
boost::regex reg("(Colo)(u)(r)",
boost::regex::icase|boost::regex::perl);

std::string s="Colour, colours, color, colourize";

s=boost::regex_replace(s,reg,"$1$3");
std::cout << s;
}

程序的输出是 "Color, colors, color, colorize". regex_replace 对于这样的文本替换非常有用。

用户常见的误解

我所见到的与Boost.Regex相关的最常见的问题与regex_match的语义有关。人们很容易忘记必须使regex_match的所有输入匹配给定的正则表达式。因此,用户常以为以下代码会返回 true.

boost::regex reg("//d*");
bool b=boost::regex_match("17 is prime",reg);

无疑这个调用永远不会得到成功的匹配。只有所有输入被 regex_match 匹配才可以返回 true!几乎所有的用户都会问为什么 regex_search 不是这样而 regex_match 是。

boost::regex reg("//d*");
bool b=boost::regex_search("17 is prime",reg);

这次肯定返回 true. 值得注意的是,你可以用一些特定的缓冲操作符来让 regex_search 象 regex_match 那样运行。/A 匹配缓冲的起始点,而 /Z 匹配缓冲的结束点,因此如果你把 /A 放在正则表达式的开始,把 /Z 放在最后,你就可以让 regex_search 象 regex_match 那样使用,即必须匹配所有输入。以下正则表达式要求所有输入被匹配掉,而不管你使用的是 regex_match 或是 regex_search.

boost::regex reg("//A//d*//Z");

请记住,这并不表示可以无需使用 regex_match;相反,它可以清晰地表明我们刚才说到的语义,即必须匹配所有输入。

关于重复和贪婪

另一个容易混淆的地方是关于重复的贪婪。有些重复,如 + 和 *,是贪婪的。即是说,它们会消耗掉尽可能多的输入。以下正则表达式并不罕见,它用于在一个贪婪的重复后捕获两个数字。

boost::regex reg("(.*)(//d{2})");

这个正则表达式是对的,但它可能不能匹配你想要的子表达式!表达式 .* 会吞掉所有东西而后续的子表达式将不能匹配。以下是示范这个行为的一个例子:

int main() {
boost::regex reg("(.*)(//d{2})");
boost::cmatch m;
const char* text = "Note that I'm 31 years old, not 32.";
if(boost::regex_search(text,m, reg)) {
if (m[1].matched)
std::cout << "(.*) matched: " << m[1].str() << '/n';
if (m[2].matched)
std::cout << "Found the age: " << m[2] << '/n';
}
}

在这个程序中,我们使用了match_results的另一个特化版本,即类型 cmatch. 它就是 match_results<const char*> 的typedef, 之所以我们必须用它而不是用之前用过的 smatch,是因为我们现在是用一个字符序列调用 regex_search 而不是用类型 std::string 来调用。你期望这个程序的运行结果是什么?通常,一个刚开始使用正则表达式的用户会首先想到 m[1].matched 和 m[2].matched 都为 true, 且第二个子表达式的结果会是 "31". 接着在认识到贪婪的重复所带来的效果后,即重复会尽可能消耗输入,用户会想到只有第一个子表达式是 true,即 .* 成功地吞掉了所有的输入。最后,新用户得到了下结论,两个子表达式都被匹配,但第二个表达式匹配的是最后一个可能的序列。即第一个子表达式匹配的是 "Note that I'm 31 years old, not" 而第二个匹配 "32".

那么,如果你想使用重复并匹配另一个子表达式的第一次出现,该怎么办?要使用非贪婪的重复。在重复符后加一个 ? ,重复就变为非贪婪的了。这意味着该表达式会尝试发现最短的匹配可能而不再阻止表达式的剩余部分进行匹配。因此,要让前面的正则表达式正确工作,我们需要把它改为这样。

boost::regex reg("(.*?)(//d{2})");

如果我们用这个正则表达式来修改程序,那么 m[1].matched 和 m[2].matched 都会为 true. 表达式 .*? 只消耗最少可能的输入,即它将在第一个字符 3处停止,因为这就是表达式要成功匹配所需要的。因此,第一个子表达式会匹配 "Note that I'm" 而第二个匹配 "31".

看一下 regex_iterator

我们已经看过如何用几次 regex_search 调用来处理所有输入,但另一方面,更为优雅的方法是使用 regex_iterator. 这个迭代器类型用一个序列来列举正则表达式的所有匹配。解引用一个 regex_iterator 会产生对一个 match_results 实例的引用。构造一个 regex_iterator 时,你要把指示输入序列的迭代器传给它,并提供相应的正则表达式。我们来看一个例子,输入数据是一组由逗号分隔的整数。相应的正则表达式很简单。

boost::regex reg("(//d+),?");

在正则表达式的最后加一个 ? (匹配零次或一次) 确保最后一个数字可以被成功分析,即使输入序列不是以逗号结束。另外,我们还使用了另一个重复符 +. 这个重复符表示匹配一次或多次。现在,不需要多次调用 regex_search, 我们创建一个 regex_iterator, 并调用算法 for_each, 传给它一个函数对象,该函数对象以迭代器的解引用进行调用。下面是一个接受任意形式的match_results的函数对象,它有一个泛型的调用操作符。它所执行的就是把当前匹配的值加到一个总和中(在我们的正则表达式中,第一个子表达式是我们要用的)。

class regex_callback {
int sum_;
public:
regex_callback() : sum_(0) {}

template <typename T> void operator()(const T& what) {
sum_+=atoi(what[1].str().c_str());
}

int sum() const {
return sum_;
}
};

现在把这个函数对象的一个实例传递给 std::for_each, 结果是对每一个迭代器it的解引用调用该函数对象,即对每一次匹配的子表达式进行调用。

int main() {
boost::regex reg("(//d+),?");
std::string s="1,1,2,3,5,8,13,21";

boost::sregex_iterator it(s.begin(),s.end(),reg);
boost::sregex_iterator end;

regex_callback c;
int sum=for_each(it,end,c).sum();
}

如你所见,传递给for_each的end迭代器是 regex_iterator 一个缺省构造实例。it 和 end 的类型均为 boost::sregex_iterator, 即为 regex_iterator<std::string::const_iterator>的typedef. 这种使用 regex_iterator 的方法要比我们前面试过的多次匹配的方法更清晰,在多次匹配的方法中我们不得不在一个循环中让起始迭代器不断地前进并调用 regex_search 。

用 regex_token_iterator 分割字符串

另一个迭代器类型,或者说得更准确些,迭代器适配器,就是 boost::regex_token_iterator. 它与 regex_iterator 很类似,但却是用于列举不匹配某个正则表达式的每一个字符序列,这对于分割字符串很有用。它也可以用于选择对哪一个子表达式感兴趣,当解引用 regex_token_iterator时,只有预订的那个子表达式被返回。考虑这样一个应用程序,它接受一些用斜线号分隔的数据项作为输入。两个斜线号之间的数据组成应用程序要处理的项。使用 regex_token_iterator来分割这个字符串很容易。该正则表达式很简单。

boost::regex reg("/");

这个 regex 匹配各项间的分割符。要用它来分割输入,只需简单地把指定的索引 1 传递给 regex_token_iterator 的构造函数。以下是完整的程序:

int main() {
boost::regex reg("/");
std::string s="Split/Values/Separated/By/Slashes,";
std::vector<std::string> vec;
boost::sregex_token_iterator it(s.begin(),s.end(),reg,-1);
boost::sregex_token_iterator end;
while (it!=end)
vec.push_back(*it++);

assert(vec.size()==std::count(s.begin(),s.end(),'/')+1);
assert(vec[0]=="Split");
}

就象 regex_iterator 一样,regex_token_iterator 是一个模板类,它使用所包装的序列的迭代器类型来进行特化。这里,我们用的是 sregex_token_iterator, 它是 regex_token_iterator<std::string::const_iterator> 的 typedef 。每一次解引用这个迭代器it,它返回当前的 sub_match, 当这个迭代器前进时,它尝试再次匹配该正则表达式。这两个迭代器类型,regex_iterator 和 regex_token_iterator, 都非常有用;你应该明白,当你考虑反复调用regex_search时,就该用它们了。

更多的正则表达式

你已经看到了不少正则表达式的语法,但还有更多的要了解。这一节简单地示范一些你每天都会使用的正则表达式的其它功能。作为开始,我们先看一下一组完整的重复符;我们之前已经看到了 *, +, 以及使用 {} 进行限定重复。还有一个重复符,即是 ?. 你可能已经留意到它也可以用于声明非贪婪的重复,但对于它本身而言,它是表示一个表达式必须出现零次或一次。还有一点值得提及的是,限定重复符可以很灵活;下面是三种不同的用法:

boost::regex reg1("//d{5}");
boost::regex reg2("//d{2,4}");
boost::regex reg3("//d{2,}");

第一个正则表达式匹配5个数字。第二个匹配 2个, 3个, 或者 4个数字。第三个匹配2个或更多个数字,没有上限。

另一种重要的正则表达式特性是使用元字符 ^ 表示非字符类别。用它来表示一个匹配任意不在给定字符类别中的字符;即你所列字符类别的补集。例如,看如下正则表达式。

boost::regex reg("[^13579]");

它包含一个非字符类别,匹配任意不是奇数数字的字符。看一下以下这个小程序,试着给出程序的输出。

int main() {
boost::regex reg4("[^13579]");
std::string s="0123456789";
boost::sregex_iterator it(s.begin(),s.end(),reg4);
boost::sregex_iterator end;

while (it!=end)
std::cout << *it++;
}

你给出答案了吗?输出是 "02468",即所有偶数数字。注意,这个字符类别不仅匹配偶数数字,如果输入字符串是 "AlfaBetaGamma",那么也会全部匹配。

我们看到的这个元字符, ^, 还有另一个意思。它可以用来表示一行的开始。而元字符 $ 则表示一行的结束。

错的正则表达式

一个错的正则表达式就是一个不遵守规则的正则表达式。例如,你可能忘了一个右括号,这样正则表达式引擎将无法成功编译这个正则表达式。这时,将抛出一个 bad_expression 类型的异常。正如我前面提到的,这个异常的名字将会在下一版本的Boost.Regex中被修改,还有在即将加入Library Technical Report的版本中也是。异常类型 bad_expression 将被更名为 regex_error.

如果你的应用程序中的正则表达式全都是硬编码的,你可能不用处理错误表达式,但如果你是接受了用户的输入来作为正则表达式,你就必须准备进行错误处理。这里有一个程序,提示用户输入一个正则表达式,接着输入一个用来对正则表达式进行匹配的字符串。由用户进行输入时,总是有可能会导致无效的输入。

int main() {  
std::cout << "Enter a regular expression:/n";
std::string s;
std::getline(std::cin, s);
try {
boost::regex reg(s);
std::cout << "Enter a string to be matched:/n";

std::getline(std::cin,s);

if (boost::regex_match(s,reg))
std::cout << "That's right!/n";
else
std::cout << "No, sorry, that doesn't match./n";
}
catch(const boost::bad_expression& e) {
std::cout <<
"That's not a valid regular expression! (Error: " <<
e.what() << ") Exiting.../n";
}
}

为了保护应用程序和用户,一个 try/catch 块用于处理构造时抛出 boost::regex 的情形,这时会打印一个提示信息,而程序会温和地退出。用这个程序来测试,我们开始时输入一些合理的数据。

Enter a regular expression:
/d{5}
Enter a string to be matched:
12345
That's right!

现在,给一些错误的数据,试着输入一个错误的正则表达式。

Enter a regular expression:
(/w*))
That's not a valid regular expression! (Error: Unmatched ( or /() Exiting...

在regex reg构造时,就会抛出一个异常,因为这个正则表达式不能被编译。因此,进入到 catch 的处理例程中,程序将打印一个错误信息并退出。你只需知道有三个可能会发生异常的地方。一个是在构造一个正则表达式时,就象你刚刚看到的那样;另一个是使用成员函数 assign 把正则表达式赋给一个 regex 时。最后一个是,regex迭代器和算法也可能抛出异常,如果内存不够或者匹配的复杂度过快增长的话。

 

Regex 总结

无可争议,正则表达式是非常有用和重要的,而本库给C++带来了强大的正则表达式功能。传统上,用户除了使用POSIX C API来实现正则表达式功能以外,别无选择。对于文本处理的验证工作,正则表达式比手工编写分析代码要灵活和可靠得多。对于查找和替换,使用正则表达式可以优美地解决很多相关问题,而不用它们则根本无法解决。

Boost.Regex是一个强大的库,因此不可能在这一章中完全覆盖它所有的内容。同样,正则表达式的完美表现和广泛的应用范围意味着本章也不仅仅是简单地介绍一下它们。这个主题可以写成一本单独的书。要知道更多,可以学习Boost.Regex的在线文档,并且找一本关于正则表达式的书(考虑一下参考书目中的建议)。不论Boost.Regex有多强大,正则表达式有多广多深,初学者还是可以有效地使用本库中的正则表达式。对于那些由于C++不支持正则表达式而选择了其它语言的程序员,欢迎你们回家。

Boost.Regex并不是C++程序员唯一可以使用的正则表达式库,但它的确是最好的一个。它易于使用,并且在匹配你的正则表达式时快如闪电。你应该尽可能去用它。

Boost.Regex 的作者是 Dr. John Maddock.

 转自:http://blog.youkuaiyun.com/ck4918/archive/2007/09/12/1781926.aspx

关于Boost LIB生成名规则请看: http://scorpioemissary.spaces.live.com/blog/cns!1613d1db65d63a09!252.entry

使用boost::regex模块在C++文件中搜索类定义,并测试全局数据的程序 在 C++ 编程中,有时需要在代码中搜索特定的字符串,例如类定义。在本文中,我们将介绍如何使用 boost::regex 模块在 C++ 文件中搜索类定义,并且还会讲述如何测试全局数据。综上所述,本文介绍了如何使用 boost::regex 模块在 C++ 文件中搜索类定义,并演示了如何测试全局数据。需要注意的是,全局数据的使用应该遵循良好的编程习惯,以避免与其他部分的代码产生冲突。例如,在多线程程序中,全局数据的使用会更加复杂,需要采取相应的同步措施来保证数据的完整性。以上程序中,我们定义了一个名为。 阅读详情

相关推荐

【BOOST C++ String专题08】Boost.Regex

Boost.Regex 允许您在 C++ 中使用正则表达式。由于该库是自 C++11 以来标准库的一部分,因此如果您的开发环境支持 C++11,则无需依赖 Boost.Regex。如果包含头文件 regex,则可以在命名空间 std 中使用同名的类和函数。

gongdiwudu的专栏 5926

boost::regex的使用详解

Regex 用法详解 2008年03月15日 星期六 14:34 Regex 头文件:&amp;nbsp;“boost/regex.hpp” 正则表达式被封装为一个类型&amp;nbsp;basic_regex的对象。我们将在下一节更深入地讨论正则表达式如何被编译和分析,这里我们首先粗略地看看ba...

南极圈的博客 1万+

boost::regex模块captures相关的使用详解

上述程序中,我们使用了boost::regex模块的regex_search函数进行正则表达式的匹配。在C++中,使用boost::regex模块可以方便地进行正则表达式的匹配,并且能够获取到captures。上述程序中,我们使用了boost::regex模块的regex_iterator类,创建了一个迭代器对象begin,并使用input字符串进行初始化。在正则表达式的匹配中,captures(捕获)指的是在进行匹配过程中,正则表达式引擎捕获到的与正则表达式中括号所包含的内容相对应的内容。

2301_79330511的博客 173

Boost学习之正则表达式--regex

boost::regex类为C++提供了完整的正则表达式支持,并且已被接收为C++0x标准库。它同时也在Boost库中扮演着极重要的角色,不 少Boost子库都需要它的支持,有不少人甚至就是为了它才下载使用Boost的。 注意使用Boost.Regex需要预先编译 完整编译请参考本站编译Boost的文章 如果只要编译Regex库,有两种方法(参考链接): 在Boost根目录下运行

jiht594的专栏 9141

使用boost::regex模块进行全局类定义搜索的方法与实现

在C++中,boost::regex模块提供了一种灵活而强大的方式来进行正则表达式匹配,非常适合用于代码搜索和处理中。使用boost::regex模块可以方便地实现对C++源代码中的类定义进行全局搜索的功能。本篇文章介绍了使用boost::regex模块的方法和相关代码实现,希望能够帮助读者更好地理解和应用这个强大的正则表达式库。我们需要在一个较大的C++项目中搜索所有的类定义,并将找到的类名输出到控制台上。在实现搜索功能时,我们需要遍历所有的C++源代码文件,并对每个文件进行搜索。

HackQuestR的博客 187

boost::regex模块部分正则匹配相关的测试程序

boost::regex模块部分正则匹配相关的测试程序实现功能C++实现代码 实现功能 boost::regex模块部分正则匹配相关的测试程序 C++实现代码 #include <boost/regex.hpp> #include <string> #include <iostream> boost::regex e("(\\d{3,4})[- ]?(\\d{4})[- ]?(\\d{4})[- ]?(\\d{4})"); bool is_possible_card_nu

希望我的博客,能帮上你解决学习中工作中所遇到的问题 544

Boost::regex应用举例(一)

Normal 0 7.8 磅 0 2 false false false MicrosoftInternetExplorer4 <!-- /* Sty

newsuppy的专栏 1418

干货——Joplin私人笔记安装部署

安全、隐私、免费、不限制的私人笔记的选择和搭建

vincentho1024的专栏 7876

std::regex v.s. boost regex

目前boost regex性能更优,使用更广泛。c++11的Regular expressions library的std::regex待改进。

ChengChengCheng的博客 622

Ubuntu 24.04 高效部署Slurm集群:从零到生产环境实战

本文提供了一份在Ubuntu 24.04 LTS系统上从零开始部署生产级Slurm高性能计算集群的完整实战指南。内容涵盖网络配置、Munge安全认证、Slurm核心组件安装与配置,并深入讲解了cgroups资源隔离、NFS共享存储、配置无感知模式等生产环境优化技巧,最后通过实例演示如何提交与管理Slurm作业,帮助用户构建高效、稳定的计算平台。

weixin_29213655的博客 564

思科—OSPF多区域配置实验

实验目的:配置OSPF多区域,使得不同网段的PC互相ping通。 网络拓扑如下: R0的配置 Router>en Router#conf t Router(config)#int g0/1 Router(config-if)#ip add 192.168.1.1 255.255.255.0 Router(config-if)#no shut Router(config-if)#exit Router(config)#int g0/0 Router(config-if)#ip add 192.168.

m0_46237205的博客 1万+

使用boost::regex_search进行字符串提取

使用boost::regex_search进行字符串提取   使用正则表达式来能够处理很复杂的字符串,这里只分析以下如何使用boost::regex_search进行字符串提取。   主角登场: // boost::regex_search1 template class BidirectionalIterator, class Alloc

jfkidear的专栏 9147

OnePose++: Keypoint-Free One-Shot Object Pose Estimation without CAD Models

算法:首先采用LoFTR的细匹配模块,将粗匹配点周围的小窗口内,通过对比特征找到最相似的位置,细化当前特征点的位置。算法:PnP算法,利用3D点和2D投影点的对应关系,计算相机相对于物体的6D姿态(位置朝向)。算法:使用COLMAP,对2D粗匹配对(不依赖传统关键点匹配)进行特征轨迹计算并生成半稠密点云,每个3D点包含坐标和对应的2D投影点。算法:LoFTR粗匹配模块,将每一个像素点视为伪关键点,生成半稠密的2D匹配对。输入:优化后的3D、当前视图的2D特征点。输出:粗半稠密点云以及物体的特征轨迹。

雨落倾城的博客 885

Boost::Regex使用

背景           Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的发动机之一。 Boost库由C++标准委员会库工作组成员发起,其中有些内容有望成为下一代C++标准库内容。在C++社区中影响甚大,是不折不扣的“准”标准库。Boost由于其对跨平台的强调,对标准C++的强调,用其来进行编写平台无关的应用,是非常有帮助的。大部分boost库功能的使用只需包括相应头文件即可,少数(如正则表达式库,文件系统库等)需要链接库。在Boost库中,Regex也就是正则表达式库

杜达的专栏 1380

Mplus实战:三变量随机截距交叉滞后模型(RI-CLPM)语法详解与扩展

本文详细解析了Mplus中三变量随机截距交叉滞后模型(RI-CLPM)的构建原理与语法实现。通过将变量分解为稳定的个体间差异与动态的个体内波动,模型能更纯净地揭示多变量间的纵向交互影响。文章以工作压力、睡眠质量与工作满意度为例,提供了完整的语法模板、关键参数设置(如NOCOV命令、残差相关)及结果解读指南,帮助研究者避开常见误区,稳健分析复杂动态关系。

wdx0123456的博客 926

ADS新手必看:ICCAP数据导入与导出CSV的完整流程(附常见问题解决)

本文为ADS新手详细讲解了如何将ICCAP测试数据导入ADS进行仿真分析,并导出为通用CSV格式的完整流程。内容涵盖文件格式解析、导入设置、数据验证、处理技巧及常见问题排查,重点解决了数据文件导入过程中的兼容性与单位映射等核心难点,帮助射频工程师高效连接测量与仿真环节。

peace的博客 557

wince下单独编译boost::regex

要在wince下单独编译boost::regex 1.xinjian

kingyo的专栏 1206

计算图像哈希SHA-512

上述需要将lena.jpg放在当前目录下。

计算机视觉之光 961

【笔记】c++ - 正则表达式: GNU Regex Library、PCRE, PCRE++、Boost.Regex

GNU Regex Library 是glibc(GNU C Library)的一部分,它提供与POSIX标准兼容的正则表达式匹配的接口。是一种十分简便、灵活的文本处理工具,可以用来精确地找出某文本中匹配某种指定规则的内容。上述信用卡格式是人读的,还有机器格式:数字,15到16位长度,不分组,中间每连接符。PCRE++是一个对PCRE库的C++封装,它提供了更加方便、易用的C++接口。这四个库中,后面两个是有关系,其它都是各自己独立的,是不同的实现。在结果表达式中,可以用数字只带匹配到的结果,得到。

LawssssCat的博客 1191

五、MT8168 音频驱动之SPEAKER

本章主要讲解MT8168平台的内部SPEAKER驱动配置。分为HP接法和LINE OUT接法。2.1.3 audio_custom_exp.h设置。2.1.4 mixer_paths.xml设置。2.2.3 mixer_paths.xml设置。2.1.2 ProjectConfig 设置。2.2.2 ProjectConfig 设置。2.2.1 deconfig设置。2.1.1 DTS设置。......

Joon2020的博客 1664

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Boost::regex之正则表达式

本文是Devour Heavens为Boost::regex写的译文,版权归原作者JohnMaddock 所有,欢迎转载。但是为了尊重原作者和译者的劳动,请注明出处!谢谢! 一.简介和概述 正则表达式是模式匹配中的一种形式,经常应用在文本处理和加工。许多用户会对Unix操作系统里的命令grep、sed 、awk,以及编程语言Perl比较熟悉,其中它们都广泛大量使用了正则表达式。传统的C++用户

devourHeavens的专栏 645

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

boost::asio使用async_read_until配合boost::regex读取数据

1. 问题         很容易找到代码,boost::asio使用async_read_until配合boost::regex读取数据。但是却不知道怎么把数据从buf中读取出来。大部分示例中只有 boost::streambuf buf; /*......*/ /*when read */ cout 但是如果不cout,而是将buf的数据转到我们自己设计的变量就不知道如何是好

u010607621的博客 6087

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

boost and boost::regex for linux(Ubuntu) 编译and安装_二少_新浪博客

boost and boost::regex for linux(Ubuntu) 编译and安装_二少_新浪博客 boostandboost::regexforlinux(Ubuntu)编译and安装_二少_新浪博客1、下载Boost库 (1)...

381

boost::regex linux 中文,Boost 之正则表达式

最近做个小东西,用到了正则表达式,因为用的是C++,想赶下潮流,用下boost, 开始用boost::xpressvie, 在一台HP上一切都是正常的,然后到Sun的机器上进行编译,发现居然编译不过,晕倒了,还好及时到boost的网站上提交报告,不然自己瞎折腾,徒是浪费时间。 目前切换到 boost::regex 模块,但是遇到一问题,发现 如下正则表达式 ((0|1)+,?)+ 在对于00101...

weixin_29035147的博客 197

boost::regex_replace的使用

boost::regex_replace的常见使用方式

qq_41841073的博客 625

Boost::Regex详解【转】

要使用Boost.Regex, 你需要包含头文件"boost/regex.hpp". Regex是本书中两个需要独立编译的库之一(另一个是Boost.Signals)。你会很高兴获知如果你已经构建了Boost— —那只需在命令提示符下打一行命令——就可以自动链接了(对于Windows下的编译器),所以你不需要为指出那些库文件要用而费心。 你要做的第一件事就是声明一个类型 basic_r...

assdg2015的博客 1356
上一篇: Windows 注册表(NT4兼容格式)
下一篇: 为什么会出现LNK2005"符号已定义"的链接错误?
FreeWave
博客等级 码龄19年 9粉丝 31原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值