认识String
string可以说是我们最常用的类,但是其本质不是一个真正的类,而是一个typedef:
using string = std::basic_string<char>;
其是basic_string的特化。basic_string是C++为字符串设计的模板类,采用不同的模板搭配不同的字符类型,可以更有弹性的处理各种文字,常见的特化如下:
using wstring = std::basic_string<wchar_t>;
using u16string = std::basic_string<char16_t>;
using u32string = std::basic_string<char32_t>;
注:
ASCII不支持中文,只有Unicode支持,string就是采用的UTF-8格式支持的中文
使用String
string在C++领域虽然批评的声音很大(主要是成本太高),但是目前来说C++支持它,也没别的可用。在别无选择的情况下,我们就更要了解其优缺点,更好的使用它,以下是常见的用法:
int main()
{
std::string str = "hello world!";
str.length(); // 12
str < "xyz"; //跟strcmp一样的规则
str.substr(1, 2); //"el"
str[1]; //'e'
str.find('l'); //返回下标2
str += "!!"; //"hello world!!!"
}
字面量
C++14为了方便使用字符串新增了一个字面量字符串后缀's'
,明确的表示它是string类型的字符串,而不是C字符串,这样就可以利用auto来自动类型推导。详见下面的例子:
#include <string>
#include <iostream>
using namespace std;
using string = std::basic_string<char>;
using namespace std::literals::string_literals; //后缀s必须的命名空间
int main()
{
auto cstr = "hello world!";
auto cppstr = "hello world!"s;
cout << typeid(cstr).name() << endl; //Point const char
cout << typeid(cppstr).name() << endl; //string
}
[ik@localhost test]$ g++ -o test test.cpp
[ik@localhost test]$ ./test
PKc
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
原始字符串
C++11还为了字面量增加一个原始字符串的新标识形式,比原来的引号多了一个大写字母R和一对圆括号。详见下面的代码:
#include <string>
#include <iostream>
using namespace std;
int main()
{
auto str = R"(hello world!)";
cout << str << endl;
}
[ik@localhost test]$ g++ -o test test.cpp
[ik@localhost test]$ ./test
hello world!
其好处在于对于转移字符时,我们要打印\n
,就必须要转移\\\n
,那么在正则表达式中则是更多的\\\\\\n
:
#include <string>
#include <iostream>
using namespace std;
int main()
{
auto str1 = R"(\n)";
auto str2 = "\n";
auto str3 = "\\\n";
auto str4 = R"("'"'')";
auto str5 = "\\\\\\n";
cout << str1 << endl;
cout << str2 << endl;
cout << str3 << endl;
cout << str4 << endl;
cout << str5 << endl;
}
[ik@localhost test]$ g++ -o test test.cpp
[ik@localhost test]$ ./test
\n
\
"'"''
\\\n
可以看到,这个形式R("xxx")
,但是加入说我们要输出这个形式就需要在圆括号两边加上最多16个字符的特别界定符:
#include <string>
#include <iostream>
using namespace std;
int main()
{
auto str = R"==(R"(xxx)")==";
cout << str << endl;
}
[ik@localhost test]$ g++ -o test test.cpp
[ik@localhost test]$ ./test
R"(xxx)"
字符串转换函数
在处理字符串的时候,我们经常会遇到数字转换为字符串或者字符串转换为数字的需求,除了C函数atoi
、itoa
之外,C++也提供了一系列string的转换函数:
#include <string>
#include <iostream>
using namespace std;
int main()
{
cout << typeid(stoi("123")).name() << ": " << stoi("123") << endl;
cout << typeid(stol("123")).name() << ": " << stol("123") << endl;
cout << typeid(stod("12.3")).name() << ": " << stod("12.3") << endl;
cout << typeid(to_string(123)).name() << ": " << to_string(123) << endl;
}
[ik@localhost test]$ ./test
i: 123
l: 123
d: 12.3
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE: 123
字符串视图
字符串String被诟病的主要圆心就是它太重,其在拷贝的时候会发生深拷贝构成。在C++17中,提出了string_view这个类,其是一个字符串视图,只有字符串的指针和这个字符串的长度。所以,string_view在拷贝的时候,只会复制指针变量和长度这两个变量。
template<typename _CharT, typename _Traits = std::char_traits<_CharT>>
class basic_string_view
{
...
private:
size_t _M_len;
const _CharT* _M_str;
};
#include <string>
#include <string_view>
#include <iostream>
using namespace std;
int main()
{
string str = "hello world!";
string_view strv(str);
string_view strv_cp = strv;
cout << strv_cp << endl;
}
[ik@localhost test]$ g++ -std=c++17 -o test test.cpp
[ik@localhost test]$ ./test
hello world!
参考文献
[1] 罗剑锋.罗剑锋的C++实战笔记.极客时间