string类对象的常见构造:
void test_string1()
{string s0;string s1("hello world");string s2(s1);string s3(s1, 5, 3);string s4(s1, 5, 10);string s5(s1, 5);cout << s0 << endl;//输出空cout << s1 << endl;//输出hello worldcout << s2 << endl;//输出hello worldcout << s3 << endl;//输出 wocout << s4 << endl;//输出 worldcout << s5 << endl;//输出 worldstring s6(10, '#');cout << s6 << endl;//输出##########s0 = s6;cout << s0 << endl;//输出##########
}
模仿数组的访问:
有两个版本,第一个可读可写,第二个可读
构成运算符重载和函数重载,但是如果参数相同,只有返回值不同不能构成重载
这里不同,隐含的ths指针不同,一个是string*,一个是const string*,const修饰的是this指针指向的内容
void test_string2()
{string s1("hello world");// 下标+[]:char& operator[](size_t pos)for (size_t i = 0; i < s1.size(); i++){cout << s1[i] << " ";//本质是函数调用:cout << s1.operator[](i) << " ";}cout << endl;//可以修改for (size_t i = 0; i < s1.size(); i++){s1[i]++;}cout << endl;//普通对象可以修改string s3("hello world");s3[0]++;cout << s3 << endl;//const对象不能修改const string s2("hello world");//s2[0]++;cout << s2 << endl;cout << s3.size() << endl;cout << s3.capacity() << endl;
}
对象.at() 访问:
二者实现出来一样,显示o,但是判错不一样,这个用的少
string s1("xhello world");cout << s1[5] << endl;cout << s1.at(5) << endl;//异常捕获try{//s1[15];//这个不起作用//s1.at(15);//这个可以检查出来}catch (const exception& e){cout << e.what() << endl;}
迭代器:
行为像指针一样的类型对象
begin返回第一个位置的迭代器
end是最后一个字符的下一个位置
定义在string这个类里面的,所以使用时要指定类域
void test_string3() {string s4("hello world");//迭代器string::iterator it = s4.begin();while (it != s4.end()){cout << *it << " ";++it;}cout << endl;
}int main()
{//test_string1();//test_string2();test_string3();return 0;
}
可修改:
string::iterator it3 = s3.begin();while (it3 != s3.end()){*it3 -= 3;//修改,对每个字符减三++it3;}cout << endl;it3 = s3.begin();while (it3 != s3.end()){cout << *it3 << " ";++it3;}cout << endl;
下标+[ ]和迭代器作用一样,但是迭代器才是主流,才是容器访问的核心方式
string和顺序表适合下标+[ ],但是链表、树都不行
//顺序表vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;//链表list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int>::iterator itt = lt.begin();while (itt != lt.end()){cout << *itt << " ";++itt;}cout << endl;
// 底层就是迭代器//范围for可以遍历容器for (auto e : s3){cout << e << " ";}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;for (auto e : lt){cout << e << " ";}cout << endl;
反向迭代器:reverse_iterator
string s1("hello world");string::reverse_iterator rit = s1.rbegin();while (rit != s1.rend()){cout << *rit << " ";++rit;//还是++}cout << endl;
const迭代器: const_iterator
// const迭代器 只读const string s3("hello world");string::const_iterator it3 = s3.begin();while (it3 != s3.end()){// *it3 += 3;cout << *it3 << " ";++it3;}cout << endl;
Capacity:
size和length一样
capacity:
// 查看扩容机制string s;size_t sz = s.capacity();cout << "capacity changed: " << sz << '\n';cout << "making s grow:\n";for (int i = 0; i < 100; ++i){s.push_back('c');//自动扩容if (sz != s.capacity()){sz = s.capacity();cout << "capacity changed: " << sz << '\n';}}cout << s1 << endl;cout << s1.capacity() << endl;cout << s1.size() << endl;
clear :
shrink_to_fit:
string s1("hello worldxxxxxxxxxxxxxxx")cout << s1 << endl;cout << s1.capacity() << endl;cout << s1.size() << endl;//只清理数据,不清理空间s1.clear();cout << s1 << endl;cout << s1.capacity() << endl;cout << s1.size() << endl;// 缩容,默认缩容到15s1.shrink_to_fit();cout << s1.capacity() << endl;cout << s1.size() << endl;
reserve:
使用reserve手动扩容,请求提前开好一个空间,就不用反复扩容了,提高效率
reserve比capacity大才起作用,不会缩容
// reverse // 反转 翻转
// reserve // 保留,请求提前开好一个空间string s;s.reserve(100);//真实会比100大
resize:
比size小:删除
比size大:插入,默认插入\0
比capacity大:扩容+插入
string s2("hello worldxxxxxx");cout << s2.size() << endl;cout << s2.capacity() << endl << endl;s2.resize(10);cout << s2.size() << endl;cout << s2.capacity() << endl << endl;s2.resize(20);cout << s2.size() << endl;cout << s2.capacity() << endl << endl;s2.resize(100, 'x');cout << s2.size() << endl;cout << s2.capacity() << endl << endl;
元素访问:
前两种在上文
后两种是取头尾的字符,用[ ]也可以代替,实践中没什么用
修改:
operator+=:
+=,相当于拼接
string s3("hello world");s3 += ' ';s3 += "apple";cout << s3 << endl;
附加:append
+=用的多,这个用的少
string s1("xhello world");//只能插入一个字符 chars1.push_back('!');cout << s1 << endl;//插入字符串s1.append("hello bit");cout << s1 << endl;//插入n个字符s1.append(10, 'x');cout << s1 << endl;//迭代区间string s2(" apple ");s1.append(s2);cout << s1 << endl;//这样就少插入s2空格s1.append(++s2.begin(), --s2.end());cout << s1 << endl;
覆盖:assign
string s1("xhello world");cout << s1 << endl;s1.assign(" xxxxx");cout << s1 << endl;//xxxxx
插入:insert
少用,要挪动数据,效率不高
在pos位置之前插入
s1.insert(0, "yyyy");cout << s1 << endl;//yyyyxxxxx
删除:erase
尽量少用,要挪动数据,效率不高,和clear功能重叠
如果太短,删到结束
s1.erase(5, 3);cout << s1 << endl;s1.erase();//删空了cout << s1 << endl;
替换:replace
少用,要挪动数据,效率不高
string s2("hello world hello bit");//第五个那一个字符替换成20%s2.replace(5, 1, "20%");cout << s2 << endl;
查找:find
size_t pos = s2.find(' ');//如果找到了就继续,没找到就返回nposwhile (pos != string::npos){s2.replace(pos, 1, "20%");pos = s2.find(' ');}cout << s2 << endl;
将空格替换成20%——效率高的做法(空间换时间)
//避免在后续向 s3 中添加字符时频繁地进行内存重新分配操作s3.reserve(s2.size());for (auto ch : s2)//依次遍历字符串 s2 中的每个字符//在每次循环中,将当前字符赋值给变量 ch {if (ch != ' '){s3 += ch;}else{s3 += "20%";}}cout << s3 << endl;s2.swap(s3);
字符串操作:
查找:find
find返回的pos位置是下标,从0开始计数
size_t pos = s2.find(' ');//如果找到了就继续,没找到就返回nposwhile (pos != string::npos){s2.replace(pos, 1, "20%");pos = s2.find(' ');}cout << s2 << endl;
// 拿到文件的后缀size_t pos1 = s1.rfind('.');//rfind:从后往前找if (pos1 != string::npos){string suffix = s1.substr(pos1);//默认直接取到npos//string suffix = s1.substr(pos1, s1.size()-pos1);cout << suffix << endl;}else{cout << "没有后缀" << endl;}
生成新字符串:substr
从pos位置开始,长度为len,pos为下标
string url1("https://legacy.cplusplus.com/reference/string/string/substr/");string protocol, domain, uri;size_t i1 = url1.find(':');if (i1 != string::npos){protocol = url1.substr(0, i1 - 0);cout << protocol << endl;}// 类比strcharsize_t i2 = url1.find('/', i1 + 3);if (i2 != string::npos){domain = url1.substr(i1 + 3, i2 - (i1 + 3));cout << domain << endl;uri = url1.substr(i2 + 1);cout << uri << endl;}// 类比strstr size_t i3 = url1.find("baidu");cout << i3 << endl;
find-first-of:
std::string str("Please, replace the vowels in this sentence by asterisks.");cout << str << endl;// 类比strtokstd::size_t found = str.find_first_not_of("aeiou");while (found != std::string::npos){str[found] = '*';found = str.find_first_not_of("aeiou", found + 1);}cout << str << endl;
运算符重载:
//比大小按照ASCII码比cout << (url1 < url2) << endl;string ss1 = "xxx";//单参数构造函数支持隐式类型转换,char srtingstring ss2 = "yyy";string ret = ss1 + ss2;cout << ret << endl;string ret1 = ss1 + "yyyy";string ret2 = "yyyy" + ss2;
转换:
int i = 1234;double d = 11.22;string s1 = to_string(i);string s2 = to_string(d);string s3("45.55");double d3 = stod(s3);
练习:
仅反转字母
class Solution {
public:bool isLetter(char ch){if(ch>='a' && ch<='z'){return true;}if(ch>='A' && ch<='Z'){return true;}return false;}string reverseOnlyLetters(string s) {if(s.empty()){return s; }size_t begin = 0, end = s.size()-1;while(begin < end){while((begin < end) && !isLetter(s[begin])){++begin;}while((begin < end) && !isLetter(s[end])){--end;}swap(s[begin], s[end]);++begin;--end;}return s;}};
字符串中的第一个唯一字符
class Solution {
public:int firstUniqChar(string s) {int count[256] = {0};for(int i = 0; i < s.size(); i++){count[s[i]] += 1;}for(int i = 0;i < s.size(); i++){if(count[s[i]] == 1){return i;}}return -1;}
};
class Solution {
public:int firstUniqChar(string s) {int count[26] = {0};for(auto ch : s){count[ch - 'a'] ++;}for(int i = 0;i < s.size(); i++){if(count[s[i] - 'a'] == 1){return i;}}return -1;}
};
字符串相加
class Solution {
public:string addStrings(string num1, string num2) {//存当前位数的下标int endnum1 = num1.size()-1;int endnum2 = num2.size()-1;string str;//进位int next = 0;while(endnum1 >= 0 || endnum2 >= 0){int val1 = endnum1 >= 0? num1[endnum1--]-'0' :0;int val2 = endnum2 >= 0? num2[endnum2--]-'0' :0;int ret = val1 + val2 + next;next = ret / 10;//只要十位ret = ret % 10;//只要个位str += (ret + '0');}if(next == 1){str += '1';}reverse(str.begin(), str.end());return str;}
};
字符串最后一个单词的长度
使用cin和scanf输入时,遇到空格和换行就默认是两个字符之间的分割,所以这里要是使用cin输入了hello nowcoder,第一次只读取hello,再cin一下才能从缓冲区读到nowcoder
使用getchar可以解决遇到空格就结束的问题,只遇到换行结束
或者使用getline
delim:边界,定界,可以自己设置结束符号
#include <iostream>
using namespace std;int main() {string str;//第一种// char ch;// ch = getchar();// while(ch != '\n'){// str += ch;// ch = getchar();// }//第二种getline(cin,str);size_t pos = str.rfind(' ');pos += 1;cout<<str.size() - pos<<endl;return 0;
}