8.3 string的输入和输出
8.3.1 使用istringstream
和之前的文件的输入和输出一样
string的io类型也有三个类别,分别是
istringstream
ostrngstream
stringstream
同样这三个类都是iostream的子类。
他们有自己的操作。
和文件的输入和输出的操作不一样的是,这里传入的s不是关联字符串,而是保存s的拷贝
istringstream
如果我想处理处理字符串中的单个单词,我们可以使用istringstream。
所谓的单个单词,就是使用空格作为间隔的一串字符
"123 321 321"
可以看作三个单词。
ostringstream
如果我们想向string中添加内容时,我们可以使用ostringstream,这样做有时比字符串拼接更方便。
因为字符串拼接会一直创建对象,+一次,创建一个,而ostringstream则是输入到字符串的流中,再统一操作,这样提高了性能。
另一方面,数值类型是无法直接用"+"拼接为字符串的,但是我们使用ostringstream对象来完成。
示例如下:
ostringstream scout;
int a = 1;
double b = 3.123;
char c = 'd';
scout << a << " " << b << " " << c;
cout << scout.str();
string str = "";
str + 1;//error 错误,string标准库没有重载此操作符
练习
8.9
istream& get_istream(istream& temp_cin) {
string content = "";
auto old_state = temp_cin.rdstate();
while (true) {
temp_cin >> content;
cout << content << endl;
if (temp_cin.eof()) {
temp_cin.setstate(old_state);
break;
}
}
return temp_cin;
}
string str = "人们需要希望 英雄永垂不朽";
//关联一个字符串对象
istringstream sin(str);
get_istream(sin);
8.10
string temp_str;
std::vector<string> vec = {"今天是2020/2/7 距离开学还有xx天","天气太冷了 圣三一就要追来了","劳拉"};
for (const auto & str :vec) {
istringstream sin(str);
while (sin >> temp_str) {
cout << temp_str << endl;
}
}
8.11
string line, word;
std::vector<PersonInfo> people;
istringstream record;
//istringstream record(line);//错误,因为保存的是line的拷贝
while (std::getline(cin,line)) {
PersonInfo info;
record.str(line);
record >> info.name;
//cout << info.name << endl;
while (record>>word)
{
info.phones.push_back(word);
}
people.push_back(info);
record.clear();
}
for (const auto &item:people) {
cout << item.name<<std::ends;
for (const auto& temp_phone:item.phones) {
cout << temp_phone << std::ends;
}
cout << endl;
}
8.12
string对象的默认初始化为空字符,并不会产生未定义的行为,所以可以不使用类内初始化。‘
8.3.2使用ostringstream
练习
8.13
string line, word;
std::vector<PersonInfo> people;
istringstream record;
ifstream fin("phone.txt");
//istringstream record(line);//错误,因为保存的是line的拷贝
while (std::getline(fin,line)) {
PersonInfo info;
record.str(line);
record >> info.name;
//cout << info.name << endl;
while (record>>word)
{
info.phones.push_back(word);
}
people.push_back(info);
//状态复位,设置流的状态为有效
record.clear();
}
for (const auto &item:people) {
cout << item.name<<std::ends;
for (const auto& temp_phone:item.phones) {
cout << temp_phone << std::ends;
}
cout << endl;
}
for (const auto& entry:people) {
//因为是输出流,我们不需要使用传递一个值进去,其实输入流也是,但是读取一个空的string对象没有任何意义
ostringstream formatted, badNum;
//为什么需要向formatted和badnum中都写入内容
//因为我们无法确定,在phones中,哪一个元素不是数字
//所以两个都要记
for (const auto & nums:entry.phones) {
//直接判断是不是纯数字
if (!valid(nums)) {
//很有意思,向string对象中写入内容
badNum << " " << nums;
//
break;
}
else {
//因为不知道这里的格式化指的是什么意思,所以就直接写入了
formatted << " " << nums;
}
}
if (badNum.str().empty()) {
std::cout << entry.name << " " << formatted.str() << endl;
}
else {
std::cerr << "input errror:" << entry.name << "invalid numbers(s)" << badNum.str() << endl;
}
8.3.2
为什么是引用,因为引用可以避免拷贝操作,提高效率。
为什么是const引用,因为在代码业务上,entry和nums都不会被改动,因为防止误操作,所以声明为const引用。