STL String

STL String

String类型

包含头文件<string>
定义:

1
2
3
4
5
6
7
8
9
10
namespace std {
template < typename charT,
typename traits = char_traits<charT>,
typename Allocator = allocator<charT> >
class basic_string;
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
typedef basic_string<char16_t> u16string;
typedef basic_string<char32_t> u32string;
}

操作一览

String Operation
Available Operations Having String Parameters

构造函数与析构函数

从const char*到string有隐式类型转换,而从char到string没有。所以不能用’a’作为参数初始化string。
Constructors and Destructor of Strings

String和C风格字符串

在程序中应该持续用string,只有在马上用c-string的时候才转一下。
String转为C-String:c_str(), copy()

1
2
3
4
5
std::string s("12345");
atoi(s.c_str()) // convert string into integer
char buffer[100];
s.copy(buffer, 100); // copy at most 100 characters of s into buffer
s.copy(buffer, 100, 2); // copy at most 100 characters of s into buffer starting with the third character of s

大小与容量

  • size() and length() 等价,返回当前string有多少字符。**empty()**用于检查是否为空,快。
  • max_size() 返回当前string最多存放多少字符。string是存放在一块连续内存上的。所以该值要么受到PC的限制,要么是npos-1。
  • capacity() 返回如果不重新分配内存的话该string能存放多少字符。
  • reserve(n) n表示预留多少空间。如果不传参数就是把当前容量缩放为与当前长度相同。
  • shrink_to_fit() C++11。与reserver()无参数时相同。

注意重分配时,指针、迭代器、引用都失效。
可能导致失效的操作:swap(),从operator>>或getline()读入新值,任何非const成员函数除了operator[] / at() / bagin() / end() / rbegin() / rend()。

读取元素

索引从0开始。

  • operator [] 不检查索引是否合法。
  • at() 检查索引,不合法会抛出out_of_range。
  • front()和back() 自C++11。

比较

  • 用<,<=,>,>=进行比较是对整个string进行字典顺序的比较。
  • 用compare()成员函数,可以比较子字符串。返回一个int值,0表示相等,小于0表示小于,大于0表示大于。
1
2
3
4
5
6
std::string s("abcd");
s.compare("abcd"); // returns 0
s.compare("dcba"); // returns a value < 0(s is less)
s.compare("ab"); // returns a value > 0(s is greater)
s.compare(0,2,s,2,2); // returns a value < 0("ab" is less than "cd")
s.compare(1,2,"bcx",2); // returns 0("bc" is equal to "bc")

进行修改的操作

赋值

operator=, assign()

1
2
3
4
5
6
7
8
9
10
11
const std::string astring("othello");
std::string s;
s = astring; // assign "othello"
s = "two\nlines"; // assign a C-string
s = ' '; // assign a single character
s.assign(astring); // assign "othello"
s.assign(astring,1,3); // assign "the"
s.assign(astring,2,std::string::npos); // assign "hello"
s.assign("two\nlines"); // assign a C-string (equivaluent to operator=)
s.assign("nico",5); // assign the character array: 'n''i''c''o''\0'
s.assign(5, 'x'); // assign 5 characters: 'x''x''x''x''x'

交换

string成员函数swap()保证常数时间复杂度。

将string置空

1
2
3
4
std::string s;
s = ""; // assign the empty string
s.clear(); // clear contents
s.erase(); // erase all characters

插入与删除字符

  • append
1
2
3
4
5
6
7
8
9
10
11
12
13
const std::string astring("othello");
std::string s;
s += astring; // append "othello"
s += "two\nlines"; // append C-string
s += '\n'; // append single character
s += {'o', 'k'}; // append an initializer list of character (since C++11)
s.append(astring); // append "othello"
s.append(astring, 1, 3); // append "the"
s.append(astring, 2, std::string::npos); // append "hello"
s.append("two\nlines"); // append C-string
s.append("nico", 5); // append character array: 'n''i''c''o''\0'
s.append(5, 'x'); // append 5 characters: 'x''x''x''x''x'
s.push_back('\n'); // append single character
  • insert
1
2
3
4
5
const std::string astring("age");
std::string s("p");
s.insert(1, astring); // s: page
s.insert(1, "ersifl"); // s:persiflage
s.insert((std::string::size_type)0, 1, ' ');
  • remove and replace
1
2
3
4
5
6
std::string s = "i18n";	// s: i18n
s.replace(1, 2, "nternationalizatio"); // s: internationalization
s.erase(13); // s: international
s.erase(7, 5); // s: internal
s.pop_back(); // s:interna(since C++11)
s.replace(0,2,"ex"); // s:externa

子串截取与拼接

1
2
3
4
5
6
7
8
9
s.substr();	//returns a copy of s
s.substr(11); //returns string("ability")
s.substr(5,6); //returns string("change")
s.substr(s.find(’c’)); //returns string("changeability")
std::string s1("enter");
std::string s2("nation");
std::string i18n;
i18n = ’i’ + s1.substr(1) + s2 + "aliz" + s2.substr(1);
std::cout << "i18n means: " + i18n << std::endl; // i18n means: internationalization

查找

三种方式。

  1. member function,可以搜索:
    单个字符、字符序列、一系列字符中的某一个。
    正着搜反着搜。
    从任何位置开始搜。
  2. regex libray,可以搜索更复杂的序列。
  3. STL algorithms,可以搜索单个字符或字符序列,可以指定自己的比较标准。

Member Function
Search Functions for Strings
如果找到就返回找到的首字符的地址,如果没找到就返回npos。

1
2
3
4
5
6
7
8
9
std::string s("Hi Bill, I’m ill, so please pay the bill");
s.find("il"); //returns 4 (first substring "il")
s.find("il",10); //returns 13 (first substring "il" starting from s[10] )
s.rfind("il"); //returns 37 (last substring "il")
s.find_first_of("il"); //returns 1 (first char ’i’ or ’l’ )
s.find_last_of("il"); //returns 39 (last char ’i’ or ’l’ )
s.find_first_not_of("il"); //returns 0 (first char neither ’i’ nor ’l’ )
s.find_last_not_of("il"); //returns 36 (last char neither ’i’ nor ’l’ )
s.find("hi"); //returns npos

特殊值npos

1
2
3
4
5
6
std::string s;
std::string::size_type idx; //be careful: don’t use any other type!
idx = s.find("substring");
if (idx == std::string::npos) {
//...
}

数字转换

Numeric Conversions for Strings

迭代器操作

Iterator Operations of Strings
对std::string应用for_each()或transform()之类的算法时,可以这样写:

1
2
3
4
5
6
string s("Example String");
transform(s.cbegin(), s.cend(),
s.begin(),
[](char c) {
return tolower(c);
});

注意lambda中的参数类型为char。

例子:转化为后缀为.tmp的文件名

输入:prog.dat mydir hello. oops.tmp end.dat
输出:prog.tmp mydir.tmp hello.tmp oops.xxx end.tmp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{

string filename, basename, extname, tmpname;
const string suffix("tmp");
// for each command-line argument (which is an ordinary C-string)
for (int i = 1; i < argc; ++i)
{
// process argument as filename
filename = argv[i];
// search period in filename
string::size_type idx = filename.find('.');
if (idx == string::npos)
{
// filename does not contain any period
tmpname = filename + '.' + suffix;
}else
{
// split filename into base name and extension
// - base name contains all characters before the period
// - extension contains all characters after the period
basename = filename.substr(0, idx);
extname = filename.substr(idx+1);
if (extname.empty())
{
// contains period but no extension: append tmp
tmpname = filename;
tmpname += suffix;
}else if (extname == suffix)
{
// replace extension tmp with xxx
tmpname = filename;
tmpname.replace(idx+1, extname.size(), "xxx");
}else
{
// replace any extension with tmp
tmpname = filename;
tmpname.replace(idx+1, string::npos, suffix);
}
}
// print filename and temporary name
cout << filename << " => " << tmpname << endl;
}
system("Pause");
}

例子:把一句话的每个单词的字母逆序

把每句话中每个单词的字母反过来。如pots & pans换成stop & snap。
先读每一行,在行首找到第一个属于单词的字符,标记为起始,循环,当有起始的时候,找到第一个不属于单词的字符,标记为结束。然后反向输出起始到结束的单词。然后把起始设为结束后第一个属于单词的字符,再循环。结束一行后,输出一个换行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{

const string delims(" \t,.;");
string line;
// for every line read successfully
while (getline(cin, line))
{
string::size_type begIdx, endIdx;
// search beginning of the first word
begIdx = line.find_first_not_of(delims);
// while beginning of a word found
while (begIdx != string::npos)
{
// search end of the actual word
endIdx = line.find_first_of(delims, begIdx);
if (endIdx == string::npos)
{
// end of word is end of line
endIdx = line.length();
}
// print characters in reverse order
for (int i = endIdx - 1; i >= static_cast<int>(begIdx); --i)
{
cout << line[i];
}
cout << ' ';
// search beginning of the next word
begIdx = line.find_first_not_of(delims, endIdx);
}
cout << endl;
}
system("Pause");
}

[1] The C++ Standard Library 2nd Edition