C++中的字符串類(lèi)型
常用的C++的字符串類(lèi)型主要是std::string
。它是模板std::basic_string
的一個(gè)實(shí)例化。另外還有三個(gè)實(shí)例化std::wstring
、std::u16string
锦针、std::u32string
,不過(guò)不是很常用。
std::basic_string<T>
std::string std::basic_string<char>
std::wstring std::basic_string<wchar_t>
std::u16string std::basic_string<char16_t>
std::u32string std::basic_string<char32_t>
具體可以參考:http://en.cppreference.com/w/cpp/string/basic_string
std::string
標(biāo)準(zhǔn)庫(kù)中翼馆,std::string
的成員函數(shù)和相關(guān)的算法特別多,從上面給出的鏈接里的內(nèi)容烧栋,粗略計(jì)算一下写妥,包括所有的重載函數(shù),也有百余個(gè)了审姓。但是在實(shí)際的工作使用中珍特,很多時(shí)候,總是會(huì)感覺(jué)魔吐,C++對(duì)字符串的處理支持實(shí)在是弱爆了……感覺(jué)這個(gè)具有百余個(gè)方法的“巨”類(lèi)用起來(lái)總是捉襟見(jiàn)肘扎筒。
std::string
中的很多操作都是基于迭代器的——這樣的話(huà),很多操作酬姆,我們都需要先調(diào)用find
或者直接遍歷字符串拿到操作區(qū)間的迭代器嗜桌,然后再進(jìn)行實(shí)際的操作。成員函數(shù)中:insert
辞色、erase
骨宠、replace
都是基于迭代器的操作。
同時(shí),std::string
也沒(méi)有提供一些常用的字符串處理的方法层亿,比如:簡(jiǎn)單的大小寫(xiě)轉(zhuǎn)換桦卒,字符串連接,字符串分割等匿又。
C++11中方灾,提供了std::string的數(shù)字和字符串相互轉(zhuǎn)換的算法:
- 字符串==>數(shù)字
stoi
string to int
stol
string to long
stoll
string to long long
stoul
string to unsigned long
stoull
string to unsigned long long
stof
string to float
stod
string to double
stold
string to long double - 數(shù)字==>字符串
to_string
to_wstring
Boost中的字符串處理
Boost庫(kù)通過(guò)算法的形式,提供了一些處理C++字符串的函數(shù)碌更,雖然比起Java或者其它一些動(dòng)態(tài)語(yǔ)言還是略顯不足裕偿,但也算在一定程度上方便了我們對(duì)C++的字符串處理。
除了普通的字符串處理算法痛单,Boost庫(kù)還提供了一個(gè)正則表達(dá)式的函數(shù)庫(kù)Boost.Regex嘿棘。Boost.Regex已經(jīng)被納入到C++11的標(biāo)準(zhǔn)之中,但是我們常用的g++4.8.x(比如ubuntu14.04默認(rèn)的g++版本就是4.8.x桦他,公司的g++版本也是4.8.x)的C++標(biāo)準(zhǔn)庫(kù)還沒(méi)有實(shí)現(xiàn)正則表達(dá)式蔫巩。
實(shí)際上,g++4.8.x已經(jīng)定義了標(biāo)準(zhǔn)庫(kù)正則表達(dá)式的類(lèi)型和接口快压,但是只是占了個(gè)坑圆仔,并沒(méi)有真正實(shí)現(xiàn)……結(jié)果可以編譯通過(guò),但是運(yùn)行一直拋出異常。gcc4.9才真正實(shí)現(xiàn)了標(biāo)準(zhǔn)庫(kù)的正則表達(dá)式蔫劣。
下面通過(guò)例子介紹一個(gè)Boost提供的字符串處理算法以及Boost.Regex的用法坪郭。
Boost的字符串算法
- 頭文件:
#include <boost/algorithm/string.hpp>
- Boost的很多修改字符串的算法都提供了直接修改傳入字符串,名字不帶copy和返回一個(gè)新的字符串,名字帶copy兩個(gè)版本。
字符串大小寫(xiě)轉(zhuǎn)換
C++標(biāo)準(zhǔn)庫(kù)竟然連一個(gè)字符串大小寫(xiě)的轉(zhuǎn)換函數(shù)都沒(méi)有提供脉幢。
-
boost::algorithm::to_upper()
,boost::algorithm::to_lower()
直接修改傳入的字符串,將其轉(zhuǎn)換為對(duì)應(yīng)字符串的大寫(xiě)或小寫(xiě)歪沃。 -
boost::algorithm::to_upper_copy()
,boost::algorithm::to_lower_copy()
返回一個(gè)新的大寫(xiě)或小寫(xiě)字符串。
- 例子:
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>
using namespace std;
int main()
{
std::string s("AbCdefG123 HijkLmn");
cout << boost::algorithm::to_upper_copy(s) << endl;
boost::algorithm::to_lower(s);
cout << s << endl;
}
輸出結(jié)果:
ABCDEFG123 HIJKLMN
abcdefg123 hijklmn
子串刪除嫌松。
-
std::string
提供了幾個(gè)erase成員函數(shù)沪曙,都是基于“位置(下標(biāo)或迭代器)”的刪除:
basic_string& erase(size_type index = 0, size_type count = npos);
iterator erase(iterator position);
iterator erase(const_iterator position);
iterator erase(iterator first, iterator last);
iterator erase(const_iterator first, const_iterator last);
- STL提供的remove系列的算法,由于其需要與其他容器通用,其刪除時(shí)的比較函數(shù)只能是一個(gè)字符之間的比較(std::string中的一個(gè)字符相當(dāng)于vector中的一個(gè)元素)。
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value);
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p);
OutputIt remove_copy(InputIt first, InputIt last, OutputIt d_first, const T& value);
OutputIt remove_copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPredicate p);
- Boost提供了刪除字符串子串的算法萎羔。
erase_all()刪除主串中所有相等的子串液走。
erase_first()刪除主串中第一個(gè)相等的子串。
erase_nth()刪除主串中的第n個(gè)子串贾陷。**注意這里的n是從0開(kāi)始的缘眶。**
erase_head()刪除主串的前n個(gè)字符。
erase_tail()刪除組成的后n個(gè)字符髓废。
erase系列的copy版本
例子:
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>
using namespace std;
int main()
{
std::string s("AbCdefG123 HijkLmn");
s += s;
s += s;
string s0 = s;
cout << "Input String: " << s0 << endl;
cout << boost::algorithm::erase_all_copy(s0, "AbC") << endl;
cout << boost::algorithm::ierase_all_copy(s0, "ABC") << endl;
cout << boost::algorithm::erase_first_copy(s0, "defG123") << endl;
cout << boost::algorithm::ierase_first_copy(s0, "DEFG123") << endl;
cout << boost::algorithm::erase_nth_copy(s0, "HijkLmn", 1) << endl;
cout << boost::algorithm::ierase_nth_copy(s0, "HIJKLMN", 1) << endl;
cout << boost::algorithm::erase_head_copy(s0, 3) << endl;
cout << boost::algorithm::erase_tail_copy(s0, 5) << endl;
}
輸出結(jié)果:
Input String: AbCdefG123 HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmn
defG123 HijkLmndefG123 HijkLmndefG123 HijkLmndefG123 HijkLmn
defG123 HijkLmndefG123 HijkLmndefG123 HijkLmndefG123 HijkLmn
AbC HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmn
AbC HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmn
AbCdefG123 HijkLmnAbCdefG123 AbCdefG123 HijkLmnAbCdefG123 HijkLmn
AbCdefG123 HijkLmnAbCdefG123 AbCdefG123 HijkLmnAbCdefG123 HijkLmn
defG123 HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmn
AbCdefG123 HijkLmnAbCdefG123 HijkLmnAbCdefG123 HijkLmnAbCdefG123 Hi
子串查找
- Boost的這些字符串的find算法的返回值都是
boost::iterator_range
類(lèi)型的一對(duì)迭代器巷懈。 -
find_first()
查找第一個(gè)匹配的子串。std::string::find
能實(shí)現(xiàn)一樣的功能慌洪。(find_first
的實(shí)現(xiàn)應(yīng)該是封裝了這個(gè)成員函數(shù),不過(guò)個(gè)人感覺(jué)這個(gè)算法用起來(lái)更方便顶燕。) -
find_last()
查找最后一個(gè)匹配的子串凑保。std::string::rfind
能實(shí)現(xiàn)一樣的功能。 -
find_nth()
查找第n(n>=0)個(gè)匹配的字符串割岛。 -
find_head(s, n)
返回字符串的前n個(gè)字符愉适。 -
find_tail(s, n)
返回字符串的最后n個(gè)字符犯助。
例子:
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>
using namespace std;
int main()
{
std::string s("AbCdefG123 HijkLmn");
s += s;
s += s;
cout << "Input String: " << s << endl;
boost::iterator_range<std::string::iterator> itRange = boost::algorithm::find_first(s, "123");
cout << itRange << endl;
cout << itRange.begin() - s.begin() << endl;
cout << itRange.end() - s.begin() << endl;
itRange = boost::algorithm::find_last(s, "123");
cout << itRange << endl;
cout << itRange.begin() - s.begin() << endl;
cout << itRange.end() - s.begin() << endl;
itRange = boost::algorithm::find_nth(s, "123", 1);
cout << itRange << endl;
cout << itRange.begin() - s.begin() << endl;
cout << itRange.end() - s.begin() << endl;
itRange = boost::algorithm::find_head(s, 5);
cout << itRange << endl;
cout << itRange.begin() - s.begin() << endl;
cout << itRange.end() - s.begin() << endl;
itRange = boost::algorithm::find_tail(s, 5);
cout << itRange << endl;
cout << itRange.begin() - s.begin() << endl;
cout << itRange.end() - s.begin() << endl;
}
輸出結(jié)果:
123
7
10
123
61
64
123
25
28
AbCde
0
5
jkLmn
67
72
連接字符串
- Boost庫(kù)提供了
join()
算法接受一個(gè)字符串容器作為第一個(gè)參數(shù)癣漆,根據(jù)第二個(gè)參數(shù)將這些字符串連接起來(lái)。
例子:
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<string> sVec{"ABC", "def", "GHIJK", "123456"};
cout << boost::algorithm::join(sVec, "+**+") << endl;
}
輸出結(jié)果:
ABC+**+def+**+GHIJK+**+123456
替換字符串
std::string提供的replace成員函數(shù)的重載很多,但是都只提供了基于位置(index或iterator)的替換操作 (http://en.cppreference.com/w/cpp/string/basic_string/replace), 沒(méi)有基于子串比較再替換的操作剂买。
Boost提供了基于比較的子串替換算法惠爽。
replace_first()替換第一個(gè)匹配的字符串。
replace_nth()替換第n(n>=0)個(gè)匹配的字符串瞬哼。
replace_last()替換最后一個(gè)匹配的字符串婚肆。
replace_all()替換所有匹配的字符串。
replace系列的copy版本坐慰。
例子:
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s("AbcDeFGHIJklmn");
s += s;
s += s;
cout << "Input String: " << s << endl;
cout << boost::algorithm::replace_all_copy(s, "AbcD", "**") << endl;
cout << boost::algorithm::replace_first_copy(s, "AbcD", "**") << endl;
cout << boost::algorithm::replace_last_copy(s, "AbcD", "**") << endl;
cout << boost::algorithm::replace_nth_copy(s, "AbcD", 1, "**") << endl;
}
輸出結(jié)果:
Input String: AbcDeFGHIJklmnAbcDeFGHIJklmnAbcDeFGHIJklmnAbcDeFGHIJklmn
**eFGHIJklmn**eFGHIJklmn**eFGHIJklmn**eFGHIJklmn
**eFGHIJklmnAbcDeFGHIJklmnAbcDeFGHIJklmnAbcDeFGHIJklmn
AbcDeFGHIJklmnAbcDeFGHIJklmnAbcDeFGHIJklmn**eFGHIJklmn
AbcDeFGHIJklmn**eFGHIJklmnAbcDeFGHIJklmnAbcDeFGHIJklmn
消除字符串兩端的特殊字符
- 很多時(shí)候,我們會(huì)希望刪除字符左右兩邊的空白字符较性。Boost提供了幾個(gè)算法來(lái)實(shí)現(xiàn)這個(gè)功能。
trim_left()刪除字符串左邊的空白结胀。
trim_right()刪除字符串右邊的空白赞咙。
trim()刪除字符串左右兩邊的空白。
trim系列的copy版本糟港。
- 有時(shí)候,我們想要?jiǎng)h除的不僅僅是字符串左右兩邊的空白,而是其它一下特定的字符攀操。
trim_left_if()
trim_right_if()
trim_if()
trim_if系列的copy版本,如果`trim_left_copy_if`...
- Boost庫(kù)的if系列算法通常傳入一個(gè)"謂詞參數(shù)", 如:
is_any_of
is_space 是否是空白字符。
is_alnum是否是字母或數(shù)字秸抚。
is_alpha是否時(shí)字母速和。
is_cntrl是否控制字符。
is_digit是否十進(jìn)制數(shù)字剥汤。
is_graph是否圖形字符颠放。
is_lower是否小寫(xiě)字母。
is_print是否可打印字符吭敢。
is_punct是否標(biāo)點(diǎn)符號(hào)碰凶。
is_upper是否大寫(xiě)字符。
is_xdigit是否十六進(jìn)制數(shù)字省有。
is_from_range(from, to)是否from <= ch <= to痒留。
例子:
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s(" AbcDeF GHIJklmn ");
cout << "Input String: <" << s << '>' << endl;
cout << '<' << boost::algorithm::trim_left_copy(s) << '>' << endl;
cout << '<' << boost::algorithm::trim_right_copy(s) << '>' << endl;
cout << '<' << boost::algorithm::trim_copy(s) << '>' << endl;
cout << endl;
string s1("==ABCD Efgh=IJK==-== ");
cout << "Input String: <" << s1 << '>' << endl;
cout << '<' << boost::algorithm::trim_copy_if(s, boost::algorithm::is_any_of(" -=")) << '>' << endl;
}
輸出結(jié)果:
Input String: < AbcDeF GHIJklmn >
<AbcDeF GHIJklmn >
< AbcDeF GHIJklmn>
<AbcDeF GHIJklmn>
Input String: <==ABCD Efgh=IJK==-== >
<AbcDeF GHIJklmn>
匹配比較
starts_with(s, sub) s是否以sub開(kāi)頭, 即前綴。
ends_with(s, sub) s是否以sub結(jié)尾, 即后綴蠢沿。
contains(s, sub) s是否包含sub伸头。
例子:
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s("abcdefGHIJKLMN");
cout << boost::algorithm::starts_with(s, "abcd") << endl;
cout << boost::algorithm::starts_with(s, "abcD") << endl;
cout << boost::algorithm::ends_with(s, "MN") << endl;
cout << boost::algorithm::ends_with(s, "mn") << endl;
cout << boost::algorithm::contains(s, "efG") << endl;
cout << boost::algorithm::contains(s, "WWW") << endl;
}
輸出結(jié)果:
1
0
1
0
1
0
分割字符串
- Boost庫(kù)提供了
split
算法,根據(jù)指定的字符集合對(duì)字符串進(jìn)行分割。
例子:
#include <boost/algorithm/string.hpp>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
string s("abc 123 cde");
vector<string> sVec;
boost::algorithm::split(sVec, s, boost::algorithm::is_space());
for (auto& str : sVec)
{
cout << str << endl;
}
cout << "--------分割線(xiàn)--------" << endl;
s = " abc 123 cde ";
boost::algorithm::split(sVec, s, boost::algorithm::is_space());
for (auto& str : sVec)
{
cout << str << endl;
}
cout << "--------分割線(xiàn)--------" << endl;
s = "--abc 123--cde-";
boost::algorithm::split(sVec, s, boost::algorithm::is_any_of(" -"));
for (auto& str : sVec)
{
cout << str << endl;
}
}
輸出結(jié)果:
abc
123
cde
--------分割線(xiàn)--------
//空行
abc
123
cde
//空行
//空行
//空行
--------分割線(xiàn)--------
//空行
//空行
abc
123
//空行
cde
//空行
- 注: boost的很多(但不是全部)字符串算法都帶有忽略大小寫(xiě)的版本舷蟀,相差只是以'i'開(kāi)頭恤磷。
正則表達(dá)式
簡(jiǎn)介
簡(jiǎn)單地說(shuō)面哼,Boost提供了三個(gè)類(lèi)型和三個(gè)算法來(lái)處理正則表達(dá)式:
- 三個(gè)類(lèi)型
- 正則表達(dá)式使用
boost::regex
來(lái)表示。 - 正則表達(dá)式的匹配的子串結(jié)果使用
boost::smatch
和boost::sub_match
來(lái)表示扫步。
- 正則表達(dá)式使用
- 三個(gè)算法
- 判斷整個(gè)字符串是否與正則表達(dá)式匹配:
boost::regex_match()
- 在字符串中搜索與正則表達(dá)式匹配的子串:
boost::regex_search()
- 替換掉字符串中所有與正則表達(dá)式匹配的字串:
boost::regex_replace()
- 判斷整個(gè)字符串是否與正則表達(dá)式匹配:
關(guān)于正則表達(dá)式的學(xué)習(xí)魔策,可以參考這篇文章。
例子
** 下面通過(guò)例子和注釋簡(jiǎn)單說(shuō)明其用法河胎。**
#include <boost/regex.hpp>
#include <iostream>
#include <string>
using namespace std;
int main()
{
boost::regex rgx("(\\w+)\\s(\\w+)");
string s("abcd efgh");
// boost::regex_match() 當(dāng)字符串和正則表達(dá)式<完全匹配>的時(shí)候返回true闯袒,
// 否則返回false。
cout << boost::regex_match(s, rgx) << endl;
cout << "========分割線(xiàn)========" << endl;
// boost::regex_search() 找到第一個(gè)和正則表達(dá)式匹配的子串則返回true游岳,
// 具體匹配子串的信息存放在boost::smatch類(lèi)型的參數(shù)里政敢。否則返回false。
// boost::smatch實(shí)際上是持有boost::sub_match的元素的容器胚迫。
// boost::sub_match繼承自類(lèi)std::pair喷户,
// 對(duì)應(yīng)的匹配子串由first和second成員表示:[first, second)。
boost::smatch result;
if (boost::regex_search(s, result, rgx))
{
for (size_t i = 0; i < result.size(); ++i)
{
//result[0] 正則表達(dá)式的匹配結(jié)果访锻。
//result[1] 第一個(gè)分組的匹配結(jié)果褪尝。
//result[2] 第二個(gè)分組的匹配結(jié)果。
cout << result[i] << endl;
}
}
cout << "========分割線(xiàn)========" << endl;
rgx = "(\\w+)\\s\\w+";
if (boost::regex_search(s, result, rgx))
{
for (size_t i = 0; i < result.size(); ++i)
{
//result[0] 正則表達(dá)式的匹配結(jié)果
//result[1] 分組的匹配結(jié)果
cout << result[i] << endl;
}
}
cout << "========分割線(xiàn)========" << endl;
rgx = "\\w+\\s(\\w+)";
if (boost::regex_search(s, result, rgx))
{
for (size_t i = 0; i < result.size(); ++i)
{
cout << result[i] << endl;
}
}
cout << "========分割線(xiàn)========" << endl;
rgx = "\\w+\\s\\w+";
if (boost::regex_search(s, result, rgx))
{
for (size_t i = 0; i < result.size(); ++i)
{
cout << result[i] << endl;
}
}
cout << "========分割線(xiàn)========" << endl;
rgx = "(\\d+)\\s(\\w+)";
if (boost::regex_search(s, result, rgx))
{
for (size_t i = 0; i < result.size(); ++i)
{
cout << result[i] << endl;
}
}
cout << "========分割線(xiàn)========" << endl;
// 遍歷正則匹配整個(gè)字符串期犬。
s = "abcd efgh ijk www";
rgx = "\\w+\\s\\w+";
auto begin = s.cbegin();
auto end = s.cend();
while (boost::regex_search(begin, end, result, rgx))
{
cout << result[0] << endl;
begin = result[0].second;
}
cout << "========分割線(xiàn)========" << endl;
// boost::regex_replace() 替換掉字符串中<所有>匹配的子串河哑。
//結(jié)果輸出到一個(gè)Output Iterator。
boost::regex_replace(std::ostreambuf_iterator<char>(std::cout), s.cbegin(), s.cend(), rgx, "666666");
cout << endl;
//直接返回結(jié)果
cout << boost::regex_replace(s, rgx, "2233333") << endl; //每一個(gè)匹配
}
輸出結(jié)果:
1
========分割線(xiàn)========
abcd efgh
abcd
efgh
========分割線(xiàn)========
abcd efgh
abcd
========分割線(xiàn)========
abcd efgh
efgh
========分割線(xiàn)========
abcd efgh
========分割線(xiàn)========
========分割線(xiàn)========
abcd efgh
ijk www
========分割線(xiàn)========
666666 666666
2233333 2233333