Boost庫基礎-字符串與文本處理(string_algo)

string_algo

string_algo被設計用於處理字符串,然而處理對象並不一定是string或basic_string<T>,可以是任何符合boost.range要求的容器。容器內的元素也不一定是char或wchar_t,任何可拷貝和賦值的類型均可,但如果類型的拷貝賦值代價很高,那麼string_algo的性能會下降。

string_algo庫位於名字空間boost::algorithm,但被using語句引入到了名字空間boost,爲了使用它,需要包含頭文件

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

string_algo庫提供的算法共分五大類:

  • 大小寫轉換;
  • 判斷式與分類;
  • 修剪;
  • 查找與替換;
  • 分割與合併;

string_algo庫中的算法命名遵循了標準庫的慣例,算法名均爲小寫形式,並使用不同的詞綴來區分不同的版本,命名規則:

  • 前綴 i:大小寫不敏感(忽略大小寫);
  • 後綴_copy:不變動輸入,返回處理結果的拷貝,否則原地處理,輸入即輸出;
  • 後綴_if:需要一個作爲判斷式的函數對象,否則使用默認的判斷準則;

大小寫轉換

#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;

int main()
{
	string str("I Don't Know.\n");

	//轉換爲大寫
	cout << to_upper_copy(str) << endl;

	//原字符串不變
	cout << str << endl;

	//轉換我小寫
	to_lower(str);

	//原字符串被改變
	cout << str << endl;

	getchar();
	return 0;
}

 運行結果:

判斷式(算法)

主要檢測兩個字符串之間的關係,包含以下幾種:

  • lexicographical_compare:根據字典順序檢測一個字符串是否小於另一個;
  • starts_with:檢測一個字符串是否以另一個爲前綴;
  • ends_with:檢測一個字符串是否以另一個爲後綴;
  • contains:檢測一個字符串是否包含另一個;
  • equals:是否相等;
  • all:檢測一個字符串中的所有元素是否滿足指定的判斷式;

除了all,這些算法都有 i 前綴的版本。由於它們不變動字符串,因此沒有_copy版本。

用法:

#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;

int main()
{
	string str("Power Bomb");

	//大小寫無關檢測
	assert(iends_with(str, "bomb"));

	//大小寫敏感檢測後綴
	assert(!ends_with(str, "bomb"));

	//檢測前綴
	assert(starts_with(str, "Pow"));

	//檢測包含關係
	assert(contains(str, "er"));

	//轉換小寫
	string str2 = to_lower_copy(str);

	//大小寫轉換無關判斷
	assert(iequals(str, str2));

	string str3("power suit");

	//大小寫無關比較
	assert(ilexicographical_compare(str, str3));

	//檢測字符串均小寫
	assert(all(str2.substr(0, 5), is_lower()));

	getchar();
	return 0;
}

判斷式(函數對象) 

允許對不同類型的參數進行比較,並提供大小寫無關的形式。

  • is_equal:比較兩個對象是否相等
  • is_less:比較兩個對象是否小於關係
  • is_not_greater:比較兩個對象是否不大於關係

用法:

#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;

int main()
{
	string str1("Samus");
	string str2("samus");

	assert(!is_equal()(str1, str2));

	assert(is_less()(str1, str2));

	getchar();
	return 0;
}

注意:調用的兩個括號,第一個括號調用了函數對象的構造函數,產生一個對象,第二個纔是函數調用。

分類

用於檢測一個字符是否符合某種特性。

修剪

string_algo提供了三個修剪算法:trim_left、trim_right和trim。

修剪算法可以刪除字符串開頭或結尾部分的空格,它有_if 和_copy 兩種後綴,因此每個算法有四個版本。_if版本接受一個判斷式IsSpace,將所有被判定爲空格(IsSpace(c) == true)的字符刪除。

用法:

#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;

int main()
{
	format fmt("|%s|\n");

	string str = "  samus aran  ";

	//刪除兩端的空格
	cout << fmt % trim_copy(str) << endl;

	//刪除左端空格
	cout << fmt % trim_left_copy(str) << endl;

	//原地刪除右端空格
	trim_right(str);

	cout << fmt % str << endl;

	string str2 = "2020 Happy new Year!!!";

	//刪除左端的數字
	cout << fmt % trim_left_copy_if(str2, is_digit());

	//刪除右端的標點
	cout << fmt % trim_right_copy_if(str2, is_punct());

	//刪除兩端的標點、數字和空格
	cout << fmt % trim_copy_if(str2, is_punct() || is_digit() || is_space());

	getchar();
	return 0;
}

運行結果:

查找

string_algo算法它不返回一個迭代器(查找到的位置),而使用了boost.range庫的iterator_range返回查找到的整個區間,獲得了更多的信息,便於算法串聯和其他處理。

iterator_range 概念上類似  std::pair<iterator,iterator>,包裝了兩個迭代器,可以用begin()和end()訪問。相當於定義了一個容器的子區間。

這些算法都不變動字符串,因此沒有_copy後綴版本,但其中前三個算法有 i 前綴的版本。

使用:

#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;

int main()
{
	format fmt("|%s| . pos = %d\n");

	string str = "Long long ago , there was a king.";

	//迭代器區間
	iterator_range<string::iterator> rge;

	//查找第一次出現
	rge = find_first(str, "long");
	cout << fmt % rge % (rge.begin() - str.begin()) << endl;

	//大小寫無關找第一次出現
	rge = ifind_first(str, "long");
	cout<< fmt % rge % (rge.begin() - str.begin()) << endl;

	//找第三次出現
	rge = find_nth(str, "ng", 2);
	cout << fmt % rge % (rge.begin() - str.begin()) << endl;
	
	//取前4個字符
	rge = find_head(str, 4);
	cout << fmt % rge % (rge.begin() - str.begin()) << endl;

	//取末尾5個字符
	rge = find_tail(str, 5);
	cout << fmt % rge % (rge.begin() - str.begin()) << endl;
	
	//找不到
	rge = find_first(str, "samus");
	assert(rge.empty() && !rge);

	getchar();
	return 0;
}

替換與刪除

替換、刪除操作與查找算法非常接近,是在查找到結果後再對字符串進行處理。

前八個算法每個都有前綴 i 、後綴_copy 和組合,有4個版本,後四個則只有後綴_copy兩個版本。

用法:

#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;

int main()
{
	string str = "Samus beat the monster.\n";

	//替換第一次出現的地方
	cout << replace_first_copy(str, "Samus", "samus") << endl;

	//替換在最後一次出現的地方
	replace_last(str, "beat", "kill");
	cout << str << endl;

	//替換末尾9個字符
	replace_tail(str, 9, "ridley.\n");
	cout << str << endl;
	
	//不分大小寫刪除出現的所有位置
	cout << ierase_all_copy(str, "samus") << endl;

	//找到r字符出現第1次 將 r 替換爲 L
	cout << replace_nth_copy(str, "r", 0, "L");

	//刪除尾部8個字符
	cout << erase_tail_copy(str, 8);

	getchar();
	return 0;
}

分割

  • find_all:類似普通的查找算法,它搜索所有匹配的字符串,加入到容器中,有一個狐狸卡大小寫的前綴 i 版本。
  • spit:使用判斷式Pred來確定分割的依據,如果字符 ch 滿足判斷式 Pred(Pred(ch) == true),那麼它就是一個分隔符,spit中第4個參數可以取值爲 token_compress_on或token_compress_off,如果爲第一個,那麼當兩個分隔符連續出現時被視爲一個,如果後第二個,兩個連續的分隔符標記了一個空字符串。默認取值爲token_compress_off。

用法:

#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;

int main()
{
	string str = "A,B.C::Dd-Ee+DD";

	deque<string> d;

	//大小寫無關分割字符串
	ifind_all(d, str, "Dd");

	//遍歷deque裏字符串
	for (auto x : d)
	{
		cout << "[" << x << "]";
	}
	cout << endl;

	//存儲range對象
	list < iterator_range<string::iterator>> l;

	//使用標點分割
	split(l, str, is_any_of(",.:-+"));

	//遍歷
	for (auto x : l)
	{
		cout << "[" << x << "]";
	}
	cout << endl;

	l.clear();

	split(l, str, is_any_of(".:-"), token_compress_on);

	for (auto x : l)
	{
		cout << "[" << x << "]";
	}
	cout << endl;

	getchar();
	return 0;
}

運行截圖:

合併 

join算法是分割算法的逆運算,它把存儲在容器中的字符串連接成一個新的字符串,並且可以指定連續的分隔符。

join有一個後綴 _if 的版本。

用法:

#include <iostream>
#include <string>
#include <vector>
#include <boost/assign.hpp>
#include <boost/utility/string_ref.hpp>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;
using namespace boost::assign;

int main()
{
	//向vetor添加了4個字符
	vector<string> v = list_of("Samus")("Link")("Zelda")("Mario");

	//用+合併它們
	cout << join(v, "+") << endl;

	//lambda表達式,判斷包含a的 才合併
	cout << join_if(v, "**", [](string_ref s)
	{
		return contains(s, "a");
	});

	getchar();
	return 0;
}

運行結果:

查找(分割)迭代器

find_iterator 和 split_iterator

使用:

#include <iostream>
#include <string>
#include <vector>
#include <boost/assign.hpp>
#include <boost/utility/string_ref.hpp>
#include <boost/algorithm/string.hpp>

using namespace boost;
using namespace std;

int main()
{
	string str("Samus | | samus | | mario | |  | | Link");

	//查找迭代器定義
	typedef find_iterator<string::iterator> string_find_iterator;

	//聲明變量
	string_find_iterator pos, end;

	//遍歷
	for (pos = make_find_iterator(str, first_finder("samus", is_iequal())); pos != end; ++pos)
	{
		cout << "[" << *pos << "]";
	}
	cout << endl;

	//分割迭代器類型定義
	typedef split_iterator<string::iterator> string_split_iterator;

	//聲明變量
	string_split_iterator p, endp;
	for (p = make_split_iterator(str, first_finder(" | | ", is_equal())); p != endp; ++p)
	{
		cout << "[" << *p << "]";
	}
	cout << endl;

	getchar();
	return 0;
}

運行結果:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章