一起学习Boost标准库--Boost.StringAlgorithms库

2023-06-20,,

概述

在未使用Boost库时,使用STL的std::string处理一些字符串时,总是不顺手,特别是当用了C#/Python等语言后trim/split总要封装一个方法来处理。如果没有形成自己的common代码库,那就悲剧了,每用一次都要写一次,虽然难度不大,但是每次重复这样工作也还是比较费劲。一般通过STL进行封装如下:

// trim from start
inline std::string &LeftTrim(string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::pointer_to_unary_function<int, int>(isspace))));
return s;
} // trim from end
inline std::string &RightTrim(string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::pointer_to_unary_function<int, int>(isspace))).base(), s.end());
return s;
} // trim from both ends
inline tstring &Trim(tstring &s)
{
return LeftTrim(RightTrim(s));
} inline std::vector<string> &Split(const string &s, char delim,
std::vector<string> &elems, bool bKeepEmpty=false)
{
stringstream ss(s);
string item;
while(std::getline(ss, item, delim)) {
if(item.empty() && !bKeepEmpty)
continue;
elems.push_back(item);
}
return elems;
} inline std::vector<string> Split(const string &s, char delim) {
std::vector<tstring> elems;
return Split(s, delim, elems);
}

同时我还是那种没有common代的一类懒汉。当开始使用Boost的时候,特别是看到Boost.StringAlgorithms库时,我可以说,我内心是激动的吗?居然有一个这么顺手的工具,过去我居然没有用,为什么STL这个标准库不加上它呢?废话不多说,谨记习大大箴言:撸起袖子,就是干!

STL标准库中std::string有一些成员函数可以查找子串/访问字符和执行基本的字符串功能。std::string可以把它看成是char类型的序列容器(标准库定义如下代码),可以使用标准库中的算法进行处理,但是毕竟这些算法不是专门未字符串而写,故有时候就稍显‘笨拙‘

typedef std::basic_string<char> std::string;
typedef std::basic_string<wchar_t> std::wstring;

Boost.Boost.StringAlgorithms库的出现改变了这个局面,其内包含了非常全面的字符串算法库,提供了大量的方法来操作字符串,比如:分割/修剪/特定模式字符串查找等等一些列方法。

虽然Boost.StringAlgorithms是被设计用来处理字符串的,但是它还有更强悍的功能,并不一定是string,wstring或者任何以basic_string的模版类,可以是符合boost.range(后面回专门讲解)要求的容器,他可以是容器对象如:vector/deque/list等,不过本文主要还是定位到字符串的处理。

首先Boost.StringAlgorithms库需要包含头文件"boost/algorithm/string.hpp"中,位于命名空间boost::algorithm,但是被using语句引入到了boost命名空间。可通过如下代码进行引入:

#include <boost/algorithm/string.hpp>
using namesapce boost;

注: 该库遵循标准库的命名规范,使用小写形式,同时通过不同前后缀来区分不同版本,具体规则如下

    前缀i:忽略大小写
    后缀_copy: 不改变当前字符串,返回处理后的拷贝结果,否则就是在原字符串上进行调整操作
    后缀_if: 需要一个作为判断式的谓词函数对象

本文从如下几个方面进行介绍:

大小写转化
判断式
分类
修剪
查找及迭代器
替换和删除
分割与合并

大小写转化

Boost.StringAlgorithms库可以快速高效的将字符串进行大小写转换,主要使用如下两个方法,带后缀_copy的方法把输入转换后进行输出

to_upper();	//字符串转化成大写形式
to_lower(); //字符串转换成小写形式

测试代码:

void test_to_case()
{
string str = "The C++ Boost Libraries";
cout << str << endl;
cout << to_upper_copy(str) << endl;
cout << str << endl;
to_lower(str);
cout << str << endl;
}

输出结果如下:

The C++ Boost Libraries
THE C++ BOOST LIBRARIES
The C++ Boost Libraries
the c++ boost libraries

判断式

判断式算法可以检测两个字符串之间的关系,包括一下几种,此处我将函数对象也罗列到一起:

lexicongraphical_compare(str1, str2)	//按照字典顺序判断字符串大小
starts_with(str1, str2) //判断字符串是否以另一个开始
ends_with(str1, str2) //判断字符串是否以另一个结束
contains(str1, str2) //判断字符串是否包含另一个
equals(str1, str2) //两个字符串是否相等
all(str, pred) //检测字符串中所有元素是否满足指定谓词
is_equal()(str1,str2) //函数对象,判断字符串是否相等
is_less()(str1, str2) //函数对象,判断字符串str1是否小于str2
is_not_greater()(str1,str2) //函数对象,判断字符串str1是否不大于str2

注: 函数对象后面有两对括号,第一对括号是创建一个临时对象;第二对括号是调用操作符operator()

测试代码如下:

void test_compare_string()
{
string str = "Boost C++ Libraries";
cout.setf(std::ios::boolalpha);
cout << starts_with(str, "Boost") << endl; // true
cout << ends_with(str, "Libraries") << endl; // true
cout << contains(str, "C++") << endl; // true
cout << equals(str, to_lower_copy(str)) << endl; // false
cout << all(str, is_lower()) << endl; // false string str2 = "STL C++ Libraries";
cout << is_equal()(str, str2) << endl; // false string str3 = to_upper_copy(str);
cout << is_less()(str, str3) << endl; // false
}

分类

Boost.StringAlgorithms提供一组分类函数(谓词对象),检测一个字符是否符合某种特性。

is_space()	// 字符是否为空格或制表符
is_alnum() // 字符是否为字母或数字
is_alpha() // 字符是否为字母
is_cntrl() // 字符是否为控制字符
is_digit() // 字符是否为十进制数字
is_graph() // 字符是否为图形字符
is_lower() // 字符是否为小写字符
is_print() // 字符是否为可打印字符
is_punct() // 字符是否为表点字符
is_upper() // 字符是否为大写字符
is_xdigit() // 字符是否为十六进制字符
is_any_of() // 字符是否为字符序列中任意字符
if_from_range() // 字符是否位于指定区间中

这些函数并不真正检测字符,而是返回一个函数对象,通过调用函数对象的operator()来进行分类判断,内部实现如下:

 inline detail::is_classifiedF
is_alpha(const std::locale& Loc=std::locale())
{
return detail::is_classifiedF(std::ctype_base::alpha, Loc);
}

示例代码:

void test_classified()
{
std::string s = "Boost C++ Libraries";
std::vector<std::string> vs;
split(vs, s, is_space());
std::cout << vs.size() << endl; // 3
}

修剪

Boost.StringAlgorithms提供三个修剪函数,如前文我们一般实现的代码,分别修剪字符串开头或结尾的空格(该方法的_if版本可接收其他谓词对象,如上文提到的分类)

trim_left()
trim_right()
trim()

示例代码如下:

void test_trim()
{
std::string s = " Boost C++ Libraries!!!--166";
cout << trim_left_copy(s) << endl; //默认去除空格
cout << trim_right_copy_if(s, is_digit() || is_space()) << endl;//通过||组合去除数字和空格
cout << trim_copy_if(s, is_space() || is_punct() || is_digit()) << endl;
cout << trim_copy_if(s, is_any_of("! -61B")) << endl;
}

此处调用is_any_of谓词方法,生成谓词以验证作为参数传入的字符是否在给定的字符串中存在

结果如下:

Boost C++ Libraries!!!--166
Boost C++ Libraries!!!--
Boost C++ Libraries
oost C++ Libraries

查找

以下方法返回一个迭代器的pair对象boost::iterator_range,其内部定义为:std::pair<iterator, iterator>可以通过begin和hend进行访问,其实就是返回一个容器区间

find_first()	//查找字符串再输入中第一次出现的位置
find_last() //查找字符串再输入中最后一次出现的位置
find_nth() //查找字符串再输入中第N次出现的位置(其中N的索引从0开始)
find_head() //取一个字符串的N个开头,和string的substr(0,N)取字串类似
find_tail() //取一个字符串的末尾N个字符子串
find_iterator() //内部定义如下
template<typename Range1T, typename Range2T>
inline iterator_range find_first(Range1T& Input, const Range2T& Search) template<typename Range1T, typename Range2T>
inline iterator_range find_nth(Range1T& Input, const Range2T& Search, int Nth) template<typename Range1T, typename Range2T>
inline iterator_range find_head(RangeT& Input, int N)

测试代码如下:

void test_find()
{
std::string s = "Boost C++ Libraries";
iterator_range<std::string::iterator> iter = ifind_first(s, "c++");
cout << iter << endl; //C++
cout << "begin: " << *iter.begin() << ", end: " << *--iter.end() << endl; //begin: C, end: + iter = find_head(s, 5);
cout << iter << endl; //Boost
}

替换和删除

Boost.StringAlgorithms提供方法对字符串进行替换或删除操作与查找字符串方法很类似,是再查找后再对其进行替换删除操作,

replace/erase_first()	// 替换/删除一个字符串再输入中第一次出现
replace/erase_last() // 替换/删除一个字符串再输入中最后一次出现
replace/erase_nth() // 替换/删除一个字符串再输入中第N次出现
replace/erase_all() // 替换/删除一个字符串再输入中所有出现
replace/erase_head() // 替换/删除输入的开头
replace/erase_tail() // 替换/删除输入结尾

测试代码如下:

void test_replace()
{
std::string s = "Boost C++ Libraries";
cout << replace_first_copy(s, "+", "-") << endl;
cout << replace_nth_copy(s, "+", 1, "-") << endl;
cout << replace_head_copy(s, 5, "STL") << endl;
replace_last(s, "s", "s ");
cout << replace_tail_copy(s, 1, " is very good") << endl; cout << erase_first_copy(s, "C++") << endl;
cout << erase_all_copy(s, " ") << endl;
}

结果如下:

Boost C-+ Libraries
Boost C+- Libraries
STL C++ Libraries
Boost C++ Libraries is very good
Boost Libraries
BoostC++Libraries

分割与合并

Boost.StringAlgorithms提供了两个分割字符串的方法,find_all和split使用某种策略把字符串分隔成若干部分,并将分割后的字符串存入指定的容器。其中split需要给定一个谓词作为第三个参数以判断应该在字符串的哪个位置分割,find_all类似于普通的查找方法,它搜索所有匹配的字符串,加入到容器。

join是分隔算法的逆运算,它吧存储再容器中的字符串,通过指定的分隔符练成一个新的字符串

find_iterator和split_iterator可以再字符串中像迭代器那样遍历容器,执行操作或分隔

find_all()
split()
find_iterator()
split_iterator()
join()

示例代码如下:

void test_split_and_join()
{
std::string s = "Boost C++ Libraries BOOST c++ libraries LIBRARIES LIBraries";
vector<std::string> vs;
ifind_all(vs, s, "boost");
cout << vs.size() << endl; //2 list<iterator_range<string::iterator>> items;
split(items, s, is_space());
cout <<"size: "<< items.size() //size: 9
<< " the first: " << *items.begin() << endl; // the first: Boost list<std::string> ls = assign::list_of("Boost")("C++")("Libraries");
cout << join(ls,"*") << endl; //Boost*C++*Libraries
}

一起学习Boost标准库--Boost.StringAlgorithms库的相关教程结束。

《一起学习Boost标准库--Boost.StringAlgorithms库.doc》

下载本文的Word格式文档,以方便收藏与打印。