练习 17.1:
tuple<int, int, int> threeInt( 10,20,30 );
练习 17.2:
tuple<string, vector<string>, pair<string, int>> t;
练习 17.3:
#ifndef EX17_3_H
#define EX17_3_H
#include<iostream>
#include<fstream>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<memory>
#include<tuple>
using namespace std;
using line_no = vector<string>::size_type;
using query_result = tuple<string, shared_ptr<set<line_no>>, shared_ptr<vector<string>>>;
class TextQuery
{
public:
TextQuery(ifstream& ifs);
query_result query(const string& sought) const;
private:
shared_ptr<vector<string>> file; // 输入文件
// 每个单词到它所在的行号的集合的映射
map <string, shared_ptr<set<line_no>>> wm;
};
// 打印结果
ostream& print(ostream&, const query_result&);
#endif // !EX17_3_H
#include"ex17_3.h"
#include<sstream>
TextQuery::TextQuery(ifstream& ifs) : file(new vector<string>)
{
line_no lineNo = 0;
for (string line; getline(ifs, line); ++lineNo)
{
file->push_back(line); // 保存此行文本
istringstream line_iss(line);
for (string word; line_iss >> word;)
{
// 删除标点符号
word.erase(remove_if(word.begin(), word.end(), ispunct), word.end());
// 如果单词不在wm中,以之为下标在wm中添加一项
auto& lines = wm[word];
if (!lines) // 第一次遇到这个单词时,此指针为空
lines.reset(new set<line_no>);
lines->insert(lineNo);
}
}
}
query_result TextQuery::query(const string& sought) const
{
// 如果未找到sought,我们将返回一个指向此set的指针
static shared_ptr<set<line_no>> nodata(new set<line_no>);
auto loc = wm.find(sought);
if (loc == wm.end())
return make_tuple(sought, nodata, file); // 未找到
else
return make_tuple(sought, loc->second, file);
}
// 打印结果
ostream& print(ostream& os, const query_result& qr)
{
// 如果找到了单词,打印出现次数和所有出现的位置
os << get<0>(qr) << " occurs " << get<1>(qr)->size()
<< (get<1>(qr)->size() > 1 ? " times" : " time") << endl;
// 打印单词出现的每一行
for (auto line_no : *get<1>(qr))
os << "\t(line " << line_no + 1 << ") " << *(get<2>(qr)->begin() + line_no) << endl;
return os;
}
#include"ex17_3.h"
#include<sstream>
void runQueries(ifstream& infile)
{
// infile是一个ifstream,指向我们要处理的文件
TextQuery tq(infile); // 保存文件并建立查询map
// 与用户交互:提示用户输入要查询的单词,完成查询并打印结果
while (true)
{
cout << "enter word to look for, or q to quit: ";
string s;
// 若遇到文件尾或输入‘q’时循环终止
if (!(cin >> s) || s == "q")break;
// 指向查询并打印结果
print(cout, tq.query(s)) << endl;
}
}
int main()
{
ifstream ifs("storyDataFile.txt");
runQueries(ifs);
return 0;
}
练习 17.4:
#include"Sales_data.h"
#include<tuple>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;
// matches有三个成员:一家书店的索引和两个指向书店vector中元素的迭代器
typedef tuple<vector<Sales_data>::size_type,
vector<Sales_data>::const_iterator,
vector<Sales_data>::const_iterator> matches;
// files保存每家书店的销售记录
// findBook返回一个vector,每家销售了给定书籍的书店在其中都有一项
vector<matches> findBook(const vector<vector<Sales_data>>& files, const string& book)
{
vector<matches> ret; // 初始化为空vector
// 对于每家书店,查找与给定书籍匹配的记录范围
for (auto it = files.cbegin(); it != files.cend(); ++it)
{
// 查找具有相同ISBN的Sales_data范围
auto found = equal_range(it->cbegin(), it->cend(), Sales_data(book),
[](const Sales_data& lhs, const Sales_data& rhs)
{return lhs.isbn() < rhs.isbn(); });
if (found.first != found.second) // 此书店销售了给定书籍
ret.push_back(make_tuple(it - files.cbegin(), found.first, found.second));
}
return ret; // 如果未找到匹配的销售记录,ret为空
}
void reportResults(istream& is, ostream& os, const vector<vector<Sales_data>>& files)
{
string s_book; //要查找的书
while (cout << "Enter the book ISBN to look for: ", is >> s_book)
{
auto trans = findBook(files, s_book);
if (trans.empty())
{
cout << s_book << " not found in any stores" << endl;
continue;
}
// 输出匹配的销售记录
for (const auto& store : trans)
{
auto total = accumulate(get<1>(store), get<2>(store), Sales_data(s_book));
os << "store " << get<0>(store) + 1 << " sales: " << total << endl;
}
cout << "-------------------" << endl;
}
}
#include "findBook.h"
#include <fstream>
vector<Sales_data> build_store(const string& s)
{
vector<Sales_data> ret;
ifstream ifs(s);
Sales_data item;
while (ifs >> item)
ret.push_back(item);
sort(ret.begin(), ret.end(), [](const Sales_data& lhs, const Sales_data& rhs)
{return lhs.isbn() < rhs.isbn(); });
return ret;
}
int main()
{
vector<vector<Sales_data>> files;
for (int i = 0; i != 4; ++i)
files.push_back(build_store("book_sales"));
reportResults(cin, cout, files);
}
练习 17.5:
#include"Sales_data.h"
#include<utility>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;
// matches有三个成员:一家书店的索引和两个指向书店vector中元素的迭代器
using matches = pair<vector<Sales_data>::size_type,
pair<vector<Sales_data>::const_iterator,
vector<Sales_data>::const_iterator>>;
// files保存每家书店的销售记录
// findBook返回一个vector,每家销售了给定书籍的书店在其中都有一项
vector<matches> findBook(const vector<vector<Sales_data>>& files, const string& book)
{
vector<matches> ret; // 初始化为空vector
// 对于每家书店,查找与给定书籍匹配的记录范围
for (auto it = files.cbegin(); it != files.cend(); ++it)
{
// 查找具有相同ISBN的Sales_data范围
auto found = equal_range(it->cbegin(), it->cend(), Sales_data(book),
[](const Sales_data& lhs, const Sales_data& rhs)
{return lhs.isbn() < rhs.isbn(); });
if (found.first != found.second) // 此书店销售了给定书籍
ret.push_back(make_pair(it - files.cbegin(), make_pair(found.first, found.second)));
}
return ret; // 如果未找到匹配的销售记录,ret为空
}
void reportResults(istream& is, ostream& os, const vector<vector<Sales_data>>& files)
{
string s_book; //要查找的书
while (cout << "Enter the book ISBN to look for: ", is >> s_book)
{
auto trans = findBook(files, s_book);
if (trans.empty())
{
cout << s_book << " not found in any stores" << endl;
continue;
}
// 输出匹配的销售记录
for (const auto& store : trans)
{
auto total = accumulate(store.second.first, store.second.second, Sales_data(s_book));
os << "store " << store.first + 1 << " sales: " << total << endl;
}
cout << "-------------------" << endl;
}
}
练习 17.6:
#include"Sales_data.h"
#include<tuple>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;
// Matches有三个成员:一家书店的索引和两个指向书店vector中元素的迭代器
class Matches
{
friend void reportResults(istream&, ostream&, const vector<vector<Sales_data>>&);
public:
Matches(vector<Sales_data>::size_type index,
vector<Sales_data>::const_iterator begin,
vector<Sales_data>::const_iterator end)
: _index(index), _begin(begin), _end(end){ }
private:
vector<Sales_data>::size_type _index;
vector<Sales_data>::const_iterator _begin;
vector<Sales_data>::const_iterator _end;
};
// files保存每家书店的销售记录
// findBook返回一个vector,每家销售了给定书籍的书店在其中都有一项
vector<Matches> findBook(const vector<vector<Sales_data>>& files, const string& book)
{
vector<Matches> ret; // 初始化为空vector
// 对于每家书店,查找与给定书籍匹配的记录范围
for (auto it = files.cbegin(); it != files.cend(); ++it)
{
// 查找具有相同ISBN的Sales_data范围
auto found = equal_range(it->cbegin(), it->cend(), Sales_data(book),
[](const Sales_data& lhs, const Sales_data& rhs)
{return lhs.isbn() < rhs.isbn(); });
if (found.first != found.second) // 此书店销售了给定书籍
ret.push_back(Matches(it - files.cbegin(), found.first, found.second));
}
return ret; // 如果未找到匹配的销售记录,ret为空
}
void reportResults(istream& is, ostream& os, const vector<vector<Sales_data>>& files)
{
string s_book; //要查找的书
while (cout << "Enter the book ISBN to look for: ", is >> s_book)
{
auto trans = findBook(files, s_book);
if (trans.empty())
{
cout << s_book << " not found in any stores" << endl;
continue;
}
// 输出匹配的销售记录
for (const auto& store : trans)
{
auto total = accumulate(store._begin, store._end, Sales_data(s_book));
os << "store " << store._index + 1 << " sales: " << total << endl;
}
cout << "-------------------" << endl;
}
}
练习 17.8:
输出为空,将无法得到想要的结果。
练习 17.9:
bitset<64> bitvec(32); // 一共64bits,低位为100000,高位全为0
bitset<32> bv(1010101); // 00000000000011110110100110110101
string bstr; cin >> bstr; bitset<8> bv(bstr); // 取决于输入
练习 17.10:
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
// 使用序列1, 2, 3, 5, 8, 13, 21初始化一个bitset
bitset<22> bitvec("1000000010000100101110");
cout << bitvec << endl;
// 默认初始化并置位
bitset<22> bit_default;
for (auto i : { 1, 2, 3, 5, 8, 13, 21 })
bit_default.set(i);
cout << bit_default << endl;
return 0;
}
练习 17.11_13:
#include<bitset>
using namespace std;
template<size_t N> class QuizAnswers
{
public:
QuizAnswers() = default;
QuizAnswers(const string& answers): _answers(answers){ }
// 接受一个问题编号和一个表示真假解答的值,更新测试的解答
void setAnswer(size_t index, bool value) { _answers.set(index, value); }
// 生成测验成绩
size_t score() { return this->_answers.count() * 1.0 / N * 100; }
private:
bitset<N> _answers;
};
#include"ex17_11.h"
#include <iostream>
int main()
{
QuizAnswers<10> quiz_answers_10("1100110101");
cout << quiz_answers_10.score() << endl;
QuizAnswers<100> quiz_answers_100;
for(auto i : {1,5,9,16,34,58,72,86,99})
quiz_answers_100.setAnswer(i, true);
cout << quiz_answers_100.score() << endl;
return 0;
}
练习 17.14:
#include<iostream>
#include<regex>
#include<string>
using namespace std;
int main()
{
try
{
regex r("[[::alnum::]+\\.(cpp|cxx|cc)$", regex::icase);
}
catch (regex_error e)
{
cout << e.what() << "\ncode: " << e.code() << endl;
}
return 0;
}
练习 17.15:
#include<iostream>
#include<regex>
#include<string>
using namespace std;
int main()
{
try
{
string pattern("[^c]ei");
pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
regex r(pattern);
smatch results;
string test_word;
while (cout << "enter a word, or \"q\" to quit: ", cin >> test_word)
{
if (test_word == "q") break;
if (regex_search(test_word, results, r))
cout << "Violate the rule: i before e except after c" << endl;
else
cout << test_word + " is okay." << endl;
}
}
catch (regex_error e)
{
cout << e.what() << "\ncode: " << e.code() << endl;
}
return 0;
}
练习 17.17:
#include<iostream>
#include<regex>
#include<string>
using namespace std;
int main()
{
// 查找前一个字符不是c的字符串ei
string pattern("[^c]ei");
pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
regex r(pattern, regex::icase); // 进行匹配时忽略大小写
string test_str = "receipt freind theif receive";
for (sregex_iterator it(test_str.begin(), test_str.end(), r), end_it;
it != end_it; ++it)
cout << it->str() << endl;
return 0;
}
练习 17.19:
如果m[4](或m[6])不匹配,则m[4].str()(或m[6].str())返回一个空字符串,该字符串也可以与其他分隔符进行比较。
练习 17.20:
#include<iostream>
#include<regex>
#include<string>
using namespace std;
bool valid(const smatch& m);
int main()
{
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ])?(\\d{4})";
regex r(phone);
smatch m;
string s;
while (getline(cin, s))
{
for (sregex_iterator it(s.begin(), s.end(), r), end_it; it != end_it; ++it)
{
// 检查号码格式是否合法
if (valid(*it))
cout << "valid: " << it->str() << endl;
else
cout << "not valid: " << it->str() << endl;
}
}
return 0;
}
bool valid(const smatch& m)
{
// 如果区号前有一个左括号
if (m[1].matched)
// 则区号后必须有一个右括号,之后紧跟着剩余号码或一个空格
return m[3].matched && (m[4].matched == 0 || m[4].str() == " ");
else
// 否则,区号后不能有右括号
// 另两个组成部分间的分隔符必须匹配
return !m[3].matched && m[4].str() == m[6].str();
}
练习 17.21:
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
#include<sstream>
#include<regex>
using namespace std;
struct PersonInfo
{
string name;
vector<string> phones;
};
bool valid(const smatch& m);
void read_record(istream& is, vector<PersonInfo>& people);
void output_record(ostream& os, const vector<PersonInfo>& people);
int main()
{
string filename;
cout << "Please input a record file name: ";
cin >> filename;
cout << endl;
ifstream ifs(filename);
if (!ifs)
{
cerr << "No data?" << endl;
return -1;
}
vector<PersonInfo> people;
read_record(ifs, people);
output_record(cout, people);
return 0;
}
void read_record(istream& is, vector<PersonInfo>& people)
{
string line, phone_Num; // 分别保存来自输入的一行和电话号码
while (getline(is, line))
{
PersonInfo info; // 创建一个保存此记录数据的对象
istringstream record(line); // 将记录绑定到刚读入的行
record >> info.name; // 读取名字
while (record >> phone_Num) // 读取电话号码
{
info.phones.push_back(phone_Num);
}
people.push_back(info);
}
}
void output_record(ostream& os, const vector<PersonInfo>& people)
{
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ])?(\\d{4})";
regex r(phone);
smatch m;
// 使用ostringstream
for (const auto& entry : people) // 对people中每一项
{
ostringstream formatted, badNum; // 每个循环步创建对象
for (const auto& nums : entry.phones) // 对每个电话
{
for (sregex_iterator it(nums.begin(), nums.end(), r), end_it; it != end_it; ++it)
{
if (!valid(*it))
{
badNum << " " << nums; // 将数的字符串形式存入badNum
}
else
{
formatted << " " << nums;
}
}
}
if (badNum.str().empty()) // 没有错误的电话
{
cout << entry.name << formatted.str() << endl; // 打印名字和格式化的电话
}
else // 打印名字和错误格式的电话
{
os << "error: " << entry.name << " invalid phone(s): " << badNum.str() << endl;
}
}
}
bool valid(const smatch& m)
{
// 如果区号前有一个左括号
if (m[1].matched)
// 则区号后必须有一个右括号,之后紧跟着剩余号码或一个空格
return m[3].matched && (m[4].matched == 0 || m[4].str() == " ");
else
// 否则,区号后不能有右括号
// 另两个组成部分间的分隔符必须匹配
return !m[3].matched && m[4].str() == m[6].str();
}
练习 17.22:
string phone = "(\\()?(\\d{3})(\\))?([-. ]|\\s*)?(\\d{3})([-. ]|\\s*)?(\\d{4})";
练习 17.23:
string postcode = "(\\d{5})([-])?(\\d{4})?";
regex r(postcode);
练习 17.24:
#include<iostream>
#include<string>
#include<regex>
using namespace std;
using namespace regex_constants; // 使用format_no_copy
int main()
{
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ])?(\\d{4})";
regex r(phone);
smatch m;
string s;
string fmt = "$2.$5.$7"; // 将号码格式改为ddd.ddd.dddd
while (getline(cin, s))
// format_no_copy: 不输出输入序列中未匹配的部分
cout << regex_replace(s, r, fmt, format_no_copy) << endl;
return 0;
}
练习 17.25:
#include<iostream>
#include<string>
#include<regex>
using namespace std;
using namespace regex_constants; // 使用format_no_copy
int main()
{
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ])?(\\d{4})";
regex r(phone);
smatch m;
string s;
string fmt = "$2.$5.$7"; // 将号码格式改为ddd.ddd.dddd
while (getline(cin, s))
{
// format_no_copy: 不输出输入序列中未匹配的部分
s = regex_replace(s, r, fmt, format_no_copy);
if (s.empty())
{
cout << "no match" << endl;
continue;
}
sregex_iterator it(s.begin(), s.end(), r);
cout << it->str() << endl;
}
return 0;
}
练习 17.26:
#include<iostream>
#include<string>
#include<regex>
using namespace std;
using namespace regex_constants; // 使用format_no_copy
int main()
{
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ])?(\\d{4})";
regex r(phone);
smatch m;
string s;
string fmt = "$2.$5.$7"; // 将号码格式改为ddd.ddd.dddd
while (getline(cin, s))
{
// format_no_copy: 不输出输入序列中未匹配的部分
s = regex_replace(s, r, fmt, format_no_copy);
if (s.empty())
{
cout << "no match" << endl;
continue;
}
sregex_iterator it(s.begin(), s.end(), r), end_it;
auto beg = it;
if (++beg == end_it)
{
cout << "no more than one match: " << endl;
cout << it->str() << endl;
}
else
{
cout << "after the first match:" << endl;
for(;beg != end_it; ++beg)
cout << beg->str() << endl;
}
}
return 0;
}
练习 17.27:
#include<iostream>
#include<string>
#include<regex>
using namespace std;
int main()
{
string postcode = "(\\d{5})([-])?(\\d{4})?";
regex r(postcode);
string s;
string fmt = "$1-$3"; // 将编码格式改为ddddd-dddd
while (getline(cin, s))
cout << regex_replace(s, r, fmt);
return 0;
}
练习 17.28:
#include<iostream>
#include<random>
using namespace std;
unsigned randVal()
{
static default_random_engine e;
static uniform_int_distribution<unsigned> u;
return u(e);
}
int main()
{
for (size_t i = 0; i != 10; ++i)
cout << randVal() << endl;
return 0;
}
练习 17.29:
#include<iostream>
#include<random>
using namespace std;
unsigned randVal(unsigned seed = 0)
{
static default_random_engine e(seed);
static uniform_int_distribution<unsigned> u;
return u(e);
}
int main()
{
for (size_t i = 0; i != 10; ++i)
cout << randVal(i) << endl;
return 0;
}
练习 17.30:
#include<iostream>
#include<random>
using namespace std;
unsigned randVal(unsigned seed = 0, unsigned min = 0, unsigned max = 9)
{
static default_random_engine e(seed);
static uniform_int_distribution<unsigned> u(min, max);
return u(e);
}
int main()
{
for (size_t i = 0; i != 10; ++i)
cout << randVal(i, 0, 99) << endl;
return 0;
}
练习17.31:
由于引擎返回相同的随机数序列,如果在循环内定义b和e,每次循环都会创建一个新引擎,从而每步循环都会生成相同的值;而在循环外定义,可保持引擎状态,每次得到随机数序列中的下一个值,分布对象也要保持状态,因此应该在循环外定义。
练习 17.32:
在循环内定义resp,则无法通过编译,因为do语句结束后,resp被销毁,无法进行while条件判断。
练习 17.33:
#include<iostream>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<fstream>
#include<sstream>
#include<random>
#include<ctime>
using namespace std;
map<string, vector<string>> buildMap(ifstream& map_file);
const string& transform(const string& s, const map<string, vector<string>>& m);
void word_transform(ifstream& map_file, ifstream& input);
int main()
{
ifstream ifs_map("rules"), ifs_content("text");
if (ifs_map && ifs_content)
word_transform(ifs_map, ifs_content);
return 0;
}
// 读入给定文件,建立起转换映射
map<string, vector<string>> buildMap(ifstream& map_file)
{
map<string, vector<string>> trans_map; // 保存转换规则
string key; // 要转换的单词
string pre_value; // 待处理的内容
// 读取第一个单词存入key中,行中剩余内容存入pre_value
while (map_file >> key && getline(map_file, pre_value))
{
if (pre_value.size() > 1) // 检查是否有转换规则
{
// brb: be right back是特殊个例只有一种转换方式
if (key == "brb")
{
trans_map[key].push_back(pre_value.substr(1));
continue;
}
// 查找空格位置,通过两个空格的迭代器构造string插入vector
auto prev = pre_value.begin();
auto curr = prev + 1;
for (; (curr = find_if(curr, pre_value.end(), isspace))
!= pre_value.end(); prev = curr,++curr)
trans_map[key].push_back(string(prev + 1, curr)); // 跳过prev空格
// 插入最后一个转换方式
trans_map[key].push_back(string(prev + 1, curr));
}
else
{
throw runtime_error("no rule for " + key);
}
}
return trans_map;
}
const string& transform(const string& s, const map<string, vector<string>>& m)
{
static default_random_engine e(time(0));
auto map_it = m.find(s); // 如果存在 返回指向对应元素的迭代器 否则指向尾后迭代器
if (map_it != m.cend())
{
uniform_int_distribution<unsigned> u(0, map_it->second.size() - 1);
return map_it->second[u(e)]; // 随机使用替换短语
}
else
{
return s; // 否则返回原string
}
}
void word_transform(ifstream& map_file, ifstream& input)
{
auto trans_map = buildMap(map_file); // 保存转换规则
string text; // 保存输入中的每一行
while (getline(input, text)) // 读取每一行输入
{
istringstream stream(text); // 读取每个单词
string word;
while (stream >> word)
{
// transform返回它的第一个参数或其转换之后的形式
cout << transform(word, trans_map) << " "; // 打印输出
}
cout << endl; // 完成一行的转换
}
}
练习 17.35:
#include<iostream>
using namespace std;
int main()
{
cout << "default format: " << 100 * sqrt(2.0) << '\n'
<< "scientific: " << scientific << 100 * sqrt(2.0) << '\n'
<< "fixed decimal: " << fixed << 100 * sqrt(2.0) << '\n'
<< "hexadecimal: " << uppercase << hexfloat << 100 * sqrt(2.0) << '\n'
<< "use default: " << defaultfloat << 100 * sqrt(2.0) << endl;
return 0;
}
练习 17.36:
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
cout << left << setw(20) << "default format: " << 100 * sqrt(2.0) << '\n'
<< setw(20) << "scientific: " << scientific << 100 * sqrt(2.0) << '\n'
<< setw(20) << "fixed decimal: " << fixed << 100 * sqrt(2.0) << '\n'
<< setw(20) << "hexadecimal: " << hexfloat << uppercase << 100 * sqrt(2.0) << '\n'
<< setw(20) << "use defaults: " << defaultfloat << 100 * sqrt(2.0) << "\n\n";
return 0;
}
练习 17.37:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
int main()
{
ifstream ifs("test.txt");
char arr[50];
string s;
while (ifs.getline(arr, 20))
cout << arr << endl;
return 0;
}
练习 17.39:
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
int main()
{
fstream inOut("copyOut",
fstream::ate | fstream::in | fstream::out);
if (!inOut)
{
cerr << "Unable to open file!";
return EXIT_FAILURE;
}
// inOut以ate模式打开,因此一开始就定位到其文件尾
fstream::pos_type end_mark = inOut.tellg(); // 记住原文件文件尾位置
inOut.seekg(0, fstream::beg); // 重新定位到文件开始
size_t cnt = 0; // 字节数累加器
string line;
// 继续读取的条件:还未遇到错误且还在读取原数据
while (inOut && inOut.tellg() != end_mark
&& getline(inOut, line))
{
cnt += line.size() + 1; // 加1表示换行符
auto mark = inOut.tellg(); // 记住读取位置
inOut.seekp(0, fstream::end); // 将写标记移动到文件尾
inOut << cnt; // 输出累计长度
// 如果不是最好一行,打印一个分隔符
if (mark != end_mark)
inOut << " ";
inOut.seekg(mark); // 恢复读位置
}
inOut.seekp(0, fstream::end); // 定位到文件尾
inOut << "\n"; // 在文件尾输出一个换行符
return 0;
}