使用算法非常直接。 让我们看看第一个例子
#include <boost/algorithm/string.hpp> using namespace std; using namespace boost; // ... string str1(" hello world! "); to_upper(str1); // str1 == " HELLO WORLD! " trim(str1); // str1 == "HELLO WORLD!" string str2= to_lower_copy( ireplace_first_copy( str1,"hello","goodbye")); // str2 == "goodbye world!"
此示例将 str1 转换为大写,并从字符串的开头和结尾修剪空格。 然后创建 str2 作为 str1 的副本,并将“hello”替换为“goodbye”。 此示例演示了库中使用的几个重要概念
容器参数: 与 STL 算法不同,参数不仅以迭代器的形式指定。 STL 约定允许很大的灵活性,但它有几个限制。 不可能堆叠算法,因为容器以两个参数传递。 因此,不可能使用另一个算法的返回值。 编写 to_lower(str1)
比 to_lower(str1.begin(), str1.end())
容易得多。
Boost.Range 的魔力提供了一种处理不同字符串类型的统一方法。 如果需要传递一对迭代器,可以使用 boost::iterator_range
将迭代器打包到具有兼容接口的结构中。
复制 vs. 可变: 库中的许多算法都执行输入的转换。 可以在适当的位置完成转换,改变输入序列,也可以创建转换后的输入的副本,使输入保持不变。 这些可能性都没有优于另一种,并且两者都具有不同的优点和缺点。 因此,库中同时提供了这两种方式。
算法堆叠: 复制版本返回转换后的输入作为结果,因此允许在一个表达式中简单地链接转换(即,可以编写 trim_copy(to_upper_copy(s))
)。 可变版本具有 void
返回值,以避免误用。
命名: 命名遵循标准 C++ 库的约定。 如果同一算法存在复制版本和可变版本,则可变版本没有后缀,复制版本具有后缀 _copy。 一些算法具有前缀 i(例如 ifind_first()
)。 此前缀表示该算法以不区分大小写的方式工作。
要使用该库,请包含 boost/algorithm/string.hpp
头文件。 如果需要正则表达式相关函数,请包含 boost/algorithm/string_regex.hpp
头文件。
STL 提供了一种很好的字符大小写转换方法。 不幸的是,它仅适用于单个字符,而我们想要转换字符串,
string str1("HeLlO WoRld!"); to_upper(str1); // str1=="HELLO WORLD!"
to_upper()
和 to_lower()
使用指定的区域设置转换字符串中字符的大小写。
有关更多信息,请参阅 boost/algorithm/string/case_conv.hpp
的参考。
库的一部分处理与字符串相关的谓词。 考虑这个例子
bool is_executable( string& filename ) { return iends_with(filename, ".exe") || iends_with(filename, ".com"); } // ... string str1("command.com"); cout << str1 << (is_executable(str1)? "is": "is not") << "an executable" << endl; // prints "command.com is an executable" //.. char text1[]="hello"; cout << text1 << (all( text1, is_lower() )? " is": " is not") << " written in the lower case" << endl; // prints "hello is written in the lower case"
这些谓词确定是否在各种条件下将子字符串包含在输入字符串中。 条件是:字符串以子字符串开头,以子字符串结尾,简单地包含子字符串或两个字符串是否相等。 有关更多详细信息,请参阅 boost/algorithm/string/predicate.hpp
的参考。
请注意,如果我们使用“hello world”作为测试的输入,它将输出“hello world is not written in the lower case”,因为输入字符串中的空格不是小写字母。
此外,算法 all()
检查容器的所有元素以满足谓词指定的条件。 该谓词可以是任何一元谓词,但该库提供了一堆有用的与字符串相关的谓词和组合器,可供使用。 它们位于 boost/algorithm/string/classification.hpp
头文件中。 可以使用逻辑组合器组合分类谓词以形成更复杂的表达式。 例如:is_from_range('a','z') || is_digit()
从用户解析输入时,字符串通常具有不需要的前导或尾随字符。 为了摆脱它们,我们需要 trim 函数
string str1=" hello world! "; string str2=trim_left_copy(str1); // str2 == "hello world! " string str3=trim_right_copy(str1); // str3 == " hello world!" trim(str1); // str1 == "hello world!" string phone="00423333444"; // remove leading 0 from the phone number trim_left_if(phone,is_any_of("0")); // phone == "423333444"
可以裁剪字符串右侧,左侧或两侧的空格。 对于需要删除空白以外的其他内容的情况,有 _if 变体。 使用这些变体,用户可以指定一个仿函数,该仿函数将选择要删除的空格。 可以使用分类谓词,如前一段中提到的 is_digit()
。 请参阅 boost/algorithm/string/trim.hpp
的参考。
该库包含一组查找算法。 这是一个例子
char text[]="hello dolly!"; iterator_range<char*> result=find_last(text,"ll"); transform( result.begin(), result.end(), result.begin(), bind2nd(plus<char>(), 1) ); // text = "hello dommy!" to_upper(result); // text == "hello doMMy!" // iterator_range is convertible to bool if(find_first(text, "dolly")) { cout << "Dolly is there" << endl; }
我们使用了 find_last()
在 text
中搜索“ll”。 结果在 boost::iterator_range
中给出。 此范围划定了满足查找标准的输入部分。 在我们的示例中,它是“ll”的最后一次出现。 正如我们所看到的,find_last()
算法的输入也可以是 char[],因为 Boost.Range 支持此类型。 以下几行转换结果。 请注意,boost::iterator_range
具有熟悉的 begin()
和 end()
方法,因此可以像任何其他 STL 容器一样使用它。 此外,它可以转换为 bool,因此很容易使用查找算法进行简单的包含检查。
查找算法位于 boost/algorithm/string/find.hpp
中。
查找算法可用于搜索字符串的特定部分。 替换更进一步。 在找到匹配的部分后,将其替换为其他内容。 替换是从原始的计算出来的,使用一些转换。
string str1="Hello Dolly, Hello World!" replace_first(str1, "Dolly", "Jane"); // str1 == "Hello Jane, Hello World!" replace_last(str1, "Hello", "Goodbye"); // str1 == "Hello Jane, Goodbye World!" erase_all(str1, " "); // str1 == "HelloJane,GoodbyeWorld!" erase_head(str1, 6); // str1 == "Jane,GoodbyeWorld!"
有关替换和删除函数的完整列表,请参见参考。 有很多预定义的函数用于常见用途,但是,该库允许您定义适合特定需求的自定义 replace()
。 有一个通用的 find_format()
函数,该函数接受两个参数。 第一个是 Finder 对象,第二个是 Formatter 对象。 Finder 对象是一个仿函数,用于搜索替换部分。 Formatter 对象接受 Finder 的结果(通常是对找到的子字符串的引用),并为其创建一个替换。 替换算法将两者放在一起并进行所需的替换。
有关参考,请检查 boost/algorithm/string/replace.hpp
,boost/algorithm/string/erase.hpp
和 boost/algorithm/string/find_format.hpp
。
查找算法的扩展是查找迭代器。 查找迭代器不是仅仅搜索字符串的一部分,而是允许我们迭代与指定条件匹配的子字符串。 此功能使用 Finder 逐步搜索字符串。 取消引用查找迭代器会产生一个 boost::iterator_range
对象,该对象划定了当前匹配项。
提供了两个迭代器:find_iterator
和 split_iterator
。前者迭代查找器(Finder)找到的子字符串,后者迭代这些子字符串之间的间隙。
string str1("abc-*-ABC-*-aBc"); // Find all 'abc' substrings (ignoring the case) // Create a find_iterator typedef find_iterator<string::iterator> string_find_iterator; for(string_find_iterator It= make_find_iterator(str1, first_finder("abc", is_iequal())); It!=string_find_iterator(); ++It) { cout << copy_range<std::string>(*It) << endl; } // Output will be: // abc // ABC // aBC typedef split_iterator<string::iterator> string_split_iterator; for(string_split_iterator It= make_split_iterator(str1, first_finder("-*-", is_iequal())); It!=string_split_iterator(); ++It) { cout << copy_range<std::string>(*It) << endl; } // Output will be: // abc // ABC // aBC
请注意,find 迭代器只有一个模板参数,即基础迭代器类型。 查找器在运行时指定。 这允许我们为常见的字符串类型定义一个 find 迭代器并重用它。 此外,make_*_iterator 函数有助于构造特定范围的 find 迭代器。
请参阅 boost/algorithm/string/find_iterator.hpp
中的参考。
分割算法是 find 迭代器的扩展,用于一个常见的用例。 这些算法使用 find 迭代器并将所有匹配项存储到提供的容器中。 此容器必须能够保存提取的子字符串的副本(例如 std::string
)或引用(例如 iterator_range
)。
提供了两种算法。 find_all()
查找输入中字符串的所有副本。 split()
将输入拆分为多个部分。
string str1("hello abc-*-ABC-*-aBc goodbye"); typedef vector< iterator_range<string::iterator> > find_vector_type; find_vector_type FindVec; // #1: Search for separators ifind_all( FindVec, str1, "abc" ); // FindVec == { [abc],[ABC],[aBc] } typedef vector< string > split_vector_type; split_vector_type SplitVec; // #2: Search for tokens split( SplitVec, str1, is_any_of("-*"), token_compress_on ); // SplitVec == { "hello abc","ABC","aBc goodbye" }
[hello]
表示一个 iterator_range
,用于分隔此子字符串。
第一个示例展示了如何构造一个容器来保存对所有提取的子字符串的引用。 算法 ifind_all()
将对所有以不区分大小写的方式等于 "abc" 的子字符串的引用放入 FindVec 中。
第二个示例使用 split()
将字符串 str1 分割成由字符 '-' 或 '*' 分隔的多个部分。 然后将这些部分放入 SplitVec 中。 可以指定是否连接相邻的分隔符。
更多信息请参考:boost/algorithm/string/split.hpp
。