5.3. 字符串算法库 Boost.StringAlgorithms

Boost C++ 字符串算法库 Boost.StringAlgorithms 提供了很多字符串操作函数。 字符串的类型可以是 std::stringstd::wstring 或任何其他模板类 std::basic_string 的实例。

这些函数分类别在不同的头文件定义。 例如,大小写转换函数定义在文件 boost/algorithm/string/case_conv.hpp 中。 因为 Boost.StringAlgorithms 类中包括超过20个类别和相同数目的头文件, 为了方便起见,头文件 boost/algorithm/string.hpp 包括了所有其他的头文件。 后面所有例子都会使用这个头文件。

正如上节提到的那样, Boost.StringAlgorithms 库中许多函数 都可以接受一个类型为 std::locale 的对象作为附加参数。 而此参数是可选的,如果不设置将使用默认全局区域设置。

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4. #include <clocale>
  5.  
  6. int main()
  7. {
  8. std::setlocale(LC_ALL, "German");
  9. std::string s = "Boris Schäling";
  10. std::cout << boost::algorithm::to_upper_copy(s) << std::endl;
  11. std::cout << boost::algorithm::to_upper_copy(s, std::locale("German")) << std::endl;
  12. }

函数 boost::algorithm::to_upper_copy() 用于 转换一个字符串为大写形式,自然也有提供相反功能的函数 —— boost::algorithm::to_lower_copy() 把字符串转换为小写形式。 这两个函数都返回转换过的字符串作为结果。 如果作为参数传入的字符串自身需要被转换为大(小)写形式,可以使用函数 boost::algorithm::to_upper()boost::algorithm::to_lower ()

上面的例子使用函数 boost::algorithm::to_upper_copy() 把字符串 "Boris Schäling" 转换为大写形式。 第一次调用时使用的是默认全局区域设置, 第二次调用时则明确将区域设置为德国文化。

显然后者的转换是正确的, 因为小写字母 'ä' 对应的大写形式 'Ä' 是存在的。 而在 C 区域设置中, 'ä' 是一个未知字符所以不能转换。 为了能得到正确结果,必须明确传递正确的区域设置参数或者在调用 boost::algorithm::to_upper_copy() 之前改变全局区域设置。

可以注意到,程序使用了定义在头文件 clocale 中的函数 std::setlocale() 为 C 函数进行区域设置, 因为 std::cout 使用 C 函数在屏幕上显示信息。 在设置了正确的区域后,才可以正确显示 'ä' 和 'Ä' 等元音字母。

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::locale::global(std::locale("German"));
  8. std::string s = "Boris Schäling";
  9. std::cout << boost::algorithm::to_upper_copy(s) << std::endl;
  10. std::cout << boost::algorithm::to_upper_copy(s, std::locale("German")) << std::endl;
  11. }

上述程序将全局区域设置设为德国文化,这使得对函数 boost::algorithm::to_upper_copy() 的调用 可以将 'ä' 转换为 'Ä' 。

注意到本例并没有调用函数 std::setlocale() 。 使用函数 std::locale::global() 设置全局区域设置后, 也自动进行了 C 区域设置。 实际上,C++ 程序几乎总是使用函数 std::locale::global() 进行全局区域设置, 而不是像前面的例子那样使用函数 std::setlocale()

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::locale::global(std::locale("German"));
  8. std::string s = "Boris Schäling";
  9. std::cout << boost::algorithm::erase_first_copy(s, "i") << std::endl;
  10. std::cout << boost::algorithm::erase_nth_copy(s, "i", 0) << std::endl;
  11. std::cout << boost::algorithm::erase_last_copy(s, "i") << std::endl;
  12. std::cout << boost::algorithm::erase_all_copy(s, "i") << std::endl;
  13. std::cout << boost::algorithm::erase_head_copy(s, 5) << std::endl;
  14. std::cout << boost::algorithm::erase_tail_copy(s, 8) << std::endl;
  15. }

Boost.StringAlgorithms 库提供了几个从字符串中删除单独字母的函数, 可以明确指定在哪里删除,如何删除。例如,可以使用函数 boost::algorithm::erase_all_copy() 从整个字符串中 删除特定的某个字符。 如果只在此字符首次出现时删除,可以使用函数 boost::algorithm::erase_first_copy() 。 如果要在字符串头部或尾部删除若干字符,可以使用函数 boost::algorithm::erase_head_copy()boost::algorithm::erase_tail_copy()

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::locale::global(std::locale("German"));
  8. std::string s = "Boris Schäling";
  9. boost::iterator_range<std::string::iterator> r = boost::algorithm::find_first(s, "Boris");
  10. std::cout << r << std::endl;
  11. r = boost::algorithm::find_first(s, "xyz");
  12. std::cout << r << std::endl;
  13. }

以下各个不同函数 boost::algorithm::find_first()boost::algorithm::find_last()boost::algorithm::find_nth()boost::algorithm::find_head() 以及 boost::algorithm::find_tail() 可以用于在字符串中查找子串。

所有这些函数的共同点是均返回类型为 boost::iterator_range 类 的一对迭代器。 此类起源于 Boost C++ 的 Boost.Range 库, 它在迭代器的概念上定义了“范围”。 因为操作符 <<boost::iterator_range 类重载而来, 单个搜索算法的结果可以直接写入标准输出流。 以上程序将 Boris 作为第一个结果输出而第二个结果为空字符串。

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4. #include <vector>
  5.  
  6. int main()
  7. {
  8. std::locale::global(std::locale("German"));
  9. std::vector<std::string> v;
  10. v.push_back("Boris");
  11. v.push_back("Schäling");
  12. std::cout << boost::algorithm::join(v, " ") << std::endl;
  13. }

函数 boost::algorithm::join() 接受一个字符串的容器 作为第一个参数, 根据第二个参数将这些字符串连接起来。 相应地这个例子会输出 Boris Schäling

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::locale::global(std::locale("German"));
  8. std::string s = "Boris Schäling";
  9. std::cout << boost::algorithm::replace_first_copy(s, "B", "D") << std::endl;
  10. std::cout << boost::algorithm::replace_nth_copy(s, "B", 0, "D") << std::endl;
  11. std::cout << boost::algorithm::replace_last_copy(s, "B", "D") << std::endl;
  12. std::cout << boost::algorithm::replace_all_copy(s, "B", "D") << std::endl;
  13. std::cout << boost::algorithm::replace_head_copy(s, 5, "Doris") << std::endl;
  14. std::cout << boost::algorithm::replace_tail_copy(s, 8, "Becker") << std::endl;
  15. }

Boost.StringAlgorithms 库不但提供了查找子串或删除字母的函数, 而且提供了使用字符串替代子串的函数,包括 boost::algorithm::replace_first_copy()boost::algorithm::replace_nth_copy()boost::algorithm::replace_last_copy()boost::algorithm::replace_all_copy()boost::algorithm::replace_head_copy() 以及 boost::algorithm::replace_tail_copy() 等等。 它们的使用方法同查找和删除函数是差不多一样的,所不同的是还需要 一个替代字符串作为附加参数。

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::locale::global(std::locale("German"));
  8. std::string s = "\t Boris Schäling \t";
  9. std::cout << "." << boost::algorithm::trim_left_copy(s) << "." << std::endl;
  10. std::cout << "." <<boost::algorithm::trim_right_copy(s) << "." << std::endl;
  11. std::cout << "." <<boost::algorithm::trim_copy(s) << "." << std::endl;
  12. }

可以使用修剪函数 boost::algorithm::trim_left_copy()boost::algorithm::trim_right_copy() 以及 boost::algorithm::trim_copy() 等自动去除字符串中的空格或者字符串的结束符。 什么字符是空格取决于全局区域设置。

Boost.StringAlgorithms 库的函数可以接受一个附加的谓词参数,以决定函数作用于字符串的哪些字符。 谓词版本的修剪函数相应地被命名为 boost::algorithm::trim_left_copy_if()boost::algorithm::trim_right_copy_if()boost::algorithm::trim_copy_if()

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::locale::global(std::locale("German"));
  8. std::string s = "--Boris Schäling--";
  9. std::cout << "." << boost::algorithm::trim_left_copy_if(s, boost::algorithm::is_any_of("-")) << "." << std::endl;
  10. std::cout << "." <<boost::algorithm::trim_right_copy_if(s, boost::algorithm::is_any_of("-")) << "." << std::endl;
  11. std::cout << "." <<boost::algorithm::trim_copy_if(s, boost::algorithm::is_any_of("-")) << "." << std::endl;
  12. }

以上程序调用了一个辅助函数 boost::algorithm::is_any_of() , 它用于生成谓词以验证作为参数传入的字符是否在给定的字符串中存在。使用函数 boost::algorithm::is_any_of 后,正如例子中做的那样,修剪字符串的字符被指定为连字符。 ()

Boost.StringAlgorithms 类也提供了众多返回通用谓词的辅助函数。

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::locale::global(std::locale("German"));
  8. std::string s = "123456789Boris Schäling123456789";
  9. std::cout << "." << boost::algorithm::trim_left_copy_if(s, boost::algorithm::is_digit()) << "." << std::endl;
  10. std::cout << "." <<boost::algorithm::trim_right_copy_if(s, boost::algorithm::is_digit()) << "." << std::endl;
  11. std::cout << "." <<boost::algorithm::trim_copy_if(s, boost::algorithm::is_digit()) << "." << std::endl;
  12. }

函数 boost::algorithm::is_digit() 返回的谓词在字符为数字时返回布尔值 true。 检查字符是否为大写或小写的辅助函数分别是 boost::algorithm::is_upper()boost::algorithm::is_lower() 。 所有这些函数都默认使用全局区域设置,除非在参数中指定其他区域设置。

除了检验单独字符的谓词之外, Boost.StringAlgorithms 库还提供了处理字符串的函数。

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4.  
  5. int main()
  6. {
  7. std::locale::global(std::locale("German"));
  8. std::string s = "Boris Schäling";
  9. std::cout << boost::algorithm::starts_with(s, "Boris") << std::endl;
  10. std::cout << boost::algorithm::ends_with(s, "Schäling") << std::endl;
  11. std::cout << boost::algorithm::contains(s, "is") << std::endl;
  12. std::cout << boost::algorithm::lexicographical_compare(s, "Boris") << std::endl;
  13. }

函数 boost::algorithm::starts_with()boost::algorithm::ends_with()boost::algorithm::contains()boost::algorithm::lexicographical_compare() 均可以比较两个字符串。

以下介绍一个字符串切割函数。

  1. #include <boost/algorithm/string.hpp>
  2. #include <locale>
  3. #include <iostream>
  4. #include <vector>
  5.  
  6. int main()
  7. {
  8. std::locale::global(std::locale("German"));
  9. std::string s = "Boris Schäling";
  10. std::vector<std::string> v;
  11. boost::algorithm::split(v, s, boost::algorithm::is_space());
  12. std::cout << v.size() << std::endl;
  13. }

在给定分界符后,使用函数 boost::algorithm::split() 可以将一个字符串拆分为一个字符串容器。 它需要给定一个谓词作为第三个参数以判断应该在字符串的哪个位置分割。 这个例子使用了辅助函数 boost::algorithm::is_space() 创建一个谓词,在每个空格字符处分割字符串。

本节中许多函数都有忽略字符串大小写的版本, 这些版本一般都有与原函数相似的名称,所相差的只是以 'i'.开头。 例如,与函数 boost::algorithm::erase_all_copy() 相对应的是函数 boost::algorithm::ierase_all_copy()

最后,值得注意的是类 Boost.StringAlgorithms 中许多函数都支持正则表达式。 以下程序使用函数 boost::algorithm::find_regex() 搜索正则表达式。

  1. #include <boost/algorithm/string.hpp>
  2. #include <boost/algorithm/string/regex.hpp>
  3. #include <locale>
  4. #include <iostream>
  5.  
  6. int main()
  7. {
  8. std::locale::global(std::locale("German"));
  9. std::string s = "Boris Schäling";
  10. boost::iterator_range<std::string::iterator> r = boost::algorithm::find_regex(s, boost::regex("\\w\\s\\w"));
  11. std::cout << r << std::endl;
  12. }

为了使用正则表达式,此程序使用了Boost C++ 库中的 boost::regex , 这将在下一节介绍。