部分习题解答:
17.1、17.2:
#include <iostream>
#include <tuple>
#include <string>
#include <vector>
#include <utility>
using namespace std;
int main(int argc, char **argv)
{
tuple<int, int, int> tp{ 10,20,30 };
cout << get<0>(tp) << " " << get<1>(tp) << " " << get<2>(tp) << " " << endl;
tuple<string, vector<string>, pair<string, int>> tup;
system("pause");
return 0;
}
17.3:
#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <fstream>
#include <sstream>
#include <tuple>
using namespace std;
class TextQuery {
public:
using line_no = vector<string>::size_type;
using QueryResult = tuple< string, shared_ptr<set<line_no>>, shared_ptr<vector<string>>>;
public:
TextQuery(ifstream&); //读取文本,建立联系
QueryResult query(const string&) const;
private:
shared_ptr<vector<string>> file; //输入文件
map<string, shared_ptr<set<line_no>>> wm; //单词与行号关联的map
};
TextQuery::TextQuery(ifstream& is) : file(new vector<string>)
{
string text;
while (getline(is, text)) //文件中的每一行,按行读取
{
file->push_back(text); //保存该行文本
int n = file->size() - 1; //当前文本行号
istringstream line(text); //对于行中的每一个单词
string word;
while (line >> word)
{
auto &lines = wm[word]; //得到一个shared_ptr指针
if (!lines) //如果该指针为空,则分配一个新的set
lines.reset(new set<line_no>);
lines->insert(n); //将行号插入set中
}
}
}
TextQuery::QueryResult TextQuery::query(const string &s) const
{
//如果未找到给定单词,则返回一个指针
static shared_ptr<set<line_no>> nodata(new set<line_no>);
//使用find查找,避免将单词插入到wm中
auto loc = wm.find(s);
if (loc == wm.end())
{
return QueryResult( s, nodata, file );
}
else
return QueryResult(s, loc->second, file);
}
#endif
//test.cpp
#include <iostream>
#include <tuple>
#include <string>
#include <vector>
#include <utility>
#include "TextQuery.h"
using namespace std;
ostream &print(ostream &os, const TextQuery::QueryResult &qr)
{
os << get<0>(qr) << "\n";
for (auto num : *get<1>(qr))
{
os << "\t(lint " << num + 1 << ") " << *(get<2>(qr)->begin() + num) << endl;
}
return os;
}
int main(int argc, char **argv)
{
ifstream isfile("17.txt");
if (!isfile)
{
cout << "can't open the file" << endl;
exit(1);
}
TextQuery tq(isfile);
print(cout, tq.query("c++"));
system("pause");
return 0;
}
17.4、17.5、17.6:
bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() < rhs.isbn();
}
//17.4
typedef tuple<vector<Sales_data>::size_type,
vector<Sales_data>::const_iterator,
vector<Sales_data>::const_iterator> matches;
vector<matches>
findBook(const vector<vector<Sales_data>> &files, const string &book)
{
vector<matches> ret;
for (auto it = files.cbegin(); it != files.cend(); ++it)
{
auto found = equal_range(it->cbegin(), it->cend(), book, compareIsbn);
if (found.first != found.second)
ret.push_back(make_tuple(it - files.cbegin(), found.first, found.second));
}
return ret;
}
//17.5
vector<matches_pair>
findBook(const vector<vector<Sales_data>> &files, const string &book)
{
vector<matches_pair> ret;
for (auto it = files.cbegin(); it != files.cend(); ++it)
{
auto found = equal_range(it->cbegin(), it->cend(), book, compareIsbn);
if (found.first != found.second)
ret.push_back(make_pair(it - files.cbegin(), make_pair(found.first, found.second)));
}
return ret;
}
//17.6
struct matches_struct {
vector<Sales_data>::size_type st;
vector<Sales_data>::const_iterator fir;
vector<Sales_data>::const_iterator sec;
matches_struct(vector<Sales_data>::size_type s, vector<Sales_data>::const_iterator first,
vector<Sales_data>::const_iterator second):st(s),fir(first),sec(second){}
};
vector<matches_struct>
findBook(const vector<vector<Sales_data>> &files, const string &book)
{
vector<matches_struct> ret;
for (auto it = files.cbegin(); it != files.cend(); ++it)
{
auto found = equal_range(it->cbegin(), it->cend(), book, compareIsbn);
if (found.first != found.second)
ret.push_back(matches_struct(it - files.cbegin(), found.first, found.second);
}
return ret;
}
17.7:
更倾向于tuple,相比其他更为方便
17.8:
创建的是使用Sales_data默认构造函数创建的对象,使用Sales_data()创建的书名为空,其他数据为0
17.9:
a、00000000 00000000 00000000 00000000 00000000 00000000 00000000 00100000
b、00000000 00001111 01101001 10110101
c、视输入的内容而定,但是输入的字符非0或1那么就会抛出invalid_argument异常
17.10:
#include <iostream>
#include <bitset>
using namespace std;
int main(int argc, char **argv)
{
int xulie[] = { 1,2,3,5,8,13,21 };
bitset<32> bit1;
for (auto x : xulie)
bit1.set(x);
bitset<32> bit2;
for (size_t i = 0; i < bit1.size(); ++i)
{
bit2[i] = bit1[i];
}
cout << bit1 << endl << bit2;
system("pause");
return 0;
}
17.11、17.12、17.13:
#ifndef BIT_H
#define BIT_H
#include <iostream>
#include <string>
#include <bitset>
using namespace std;
template <unsigned N>
class Bit {
bitset<N> bit;
public:
Bit() = default;
Bit(string &s) : bit(s) { }
void updata(int n, bool b) //更新测验的答案
{
bit.set(n, b);
}
template <unsigned M>
size_t text(const Bit<M> &lb, const Bit<M> &rb); //生成测验成绩
template <unsigned M>
friend ostream& operator<<(ostream &os, const Bit<M> &lb); //重载输出运算符
};
template <unsigned M>
size_t Bit<M>::text(const Bit<M> &lb, const Bit<M> &rb)
{
auto tmp = lb.bit ^ rb.bit; //找出错误问题(^是按位异或)
tmp.flip(); //将所有位翻转
return tmp.count(); //得出正确答案
}
template <unsigned M>
ostream& operator<<(ostream &os, const Bit<M> &lb)
{
os << lb.bit;
return os;
}
#endif // ! BIT_H
17.14:
#include <iostream>
#include <bitset>
#include <regex>
using namespace std;
int main(int argc, char **argv)
{
try {
regex r("[^cei");
regex f("[z-a]");
}
catch(regex_error e)
{
cout << e.what() << "\node: " << e.code() << endl;
//regex_error(error_brack): The expression contained mismatched [ and ].
//code: 4
}
try {
regex f("[z-a]");
}
catch (regex_error e)
{
cout << e.what() << "\node: " << e.code() << endl;
//regex_error(error_range): The expression contained an invalid character range, such as [b-a] in most encodings.
// code: 8
}
system("pause");
return 0;
}
17.15、17.16:
#include <iostream>
#include <bitset>
#include <regex>
using namespace std;
int main(int argc, char **argv)
{
regex r("[[:alpha:]]*[^c]ei[[:alpha:]]*", regex::icase);
string word;
smatch results;
cout << "please input word: ";
while (cin >> word)
{
if (regex_search(word, results, r))
{
cout << word << " is ok" << endl;
}
else
cout << word << " is not ok" << endl;
}
cin.clear(); //重置输入流
r = "[^c]ei";
cout << "please input word: ";
while (cin >> word)
{
if (regex_search(word, results, r))
{
cout << word << " is ok" << endl;
}
else
cout << word << " is not ok" << endl;
}
system("pause");
return 0;
}
17.17、17.18:
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
using namespace std;
int main(int argc, char **argv)
{
ifstream file("17.17.txt");
if (!file)
{
cout << "file open wrong!" << endl;
exit(1);
}
regex r("[[:alpha:]]*[^c]ei[[:alpha:]]*", regex::icase);
string tmp, str;
while (getline(file, tmp))
{
str += tmp + "\n";
}
vector<string> vec{ "albeit","beige","feint","heir","reign","their",
"counterfeit","foreign","inveigh","rein","veil","deign",
"forfeit","inveigle","seize","veineiderdown","freight",
"leisure","skein","weigheight","heifer","neigh","sleigh",
"weighteither","height","neighbour","sleight","weirfeign",
"heinous neither surfeit weird" };
for (sregex_iterator it(str.begin(), str.end(), r), end_it; it != end_it; ++it)
{
if (find(vec.begin(), vec.end(), it->str()) != vec.end())
continue;
cout << it->str() << endl;
auto pos = it->prefix().length();
pos = pos > 40 ? pos - 40 : 0;
cout << it->prefix().str().substr(pos)
<< "\n\t\t>>> " << it->str() << " <<<\n"
<< it->suffix().str().substr(0, 40)
<< endl;
}
system("pause");
return 0;
}
17.19:
m[4]和m[6]都是分隔符,两者必须是相同的,若一方不匹配或两者不相同,返回false
17.20:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
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();
}
int main(int argc, char **argv)
{
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;
}
}
system("pause");
return 0;
}
17.21:
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
struct PersonInfo {
std::string name;
std::vector<std::string> phones;
};
bool valid(const std::smatch &m);
bool read_record(std::istream &is, std::vector<PersonInfo> &people);
void format_record(std::ostream &os, const std::vector<PersonInfo> &people);
int main()
{
using namespace std;
vector<PersonInfo> people;
string filename;
cout << "enter input file name:";
cin >> filename;
ifstream fin(filename);
if (read_record(fin, people))
{
cout << "enter output file name:";
string outname;
cin >> outname;
ofstream fout(outname, ofstream::trunc); //覆盖文件:trunc
format_record(fout, people);
}
else
cout << "open file error:" << filename << endl;
system("pause");
return 0;
}
bool valid(const std::smatch &m)
{
if (m[1].matched)
return m[3].matched && (m[4].matched == 0 || m[4] == " ");
else
return !m[3].matched&&m[4].str() == m[6].str();
}
bool read_record(std::istream &is, std::vector<PersonInfo> &people)
{
if (is)
{
std::string line, word;
while (getline(is, line)) //读取一行到line
{
PersonInfo info;
std::istringstream record(line); //关联流到line,把record绑定到要读取的行line
record >> info.name; //把流中第一个字符串输入到name,这一行的第一个,也就是名字
while (record >> word)
info.phones.push_back(word);//把名字后面的电话号码保存
people.push_back(info); //添加一个联系人
}
return true;
}
else
return false;
}
void format_record(std::ostream &os, const std::vector<PersonInfo> &people)
{
std::string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})";
std::regex reg;
try {
reg.assign(phone);
}
catch (std::regex_error e)
{
std::cout << e.what() << "\ncode: " << e.code() << std::endl;
}
std::smatch m;
for (const auto &x : people)
{
std::ostringstream formatted, badNums;
for (const auto &n : x.phones)
{
for (std::sregex_iterator it(n.begin(), n.end(), reg), end_it; it != end_it; ++it)
{
if (!valid(*it))
badNums << " " << n; //将数据放入流,暂时保存
else
formatted << " " << n;
}
}
if (badNums.str().empty())
os << x.name << " " << formatted.str() << std::endl; //将流中的数据以string的形式放入os流中
else
std::cerr << "file error: " << x.name << " invalid number " << badNums.str() << std::endl;
}
}
17.22:
将
std::string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})";
改为
string phone = "(\\()?(\\d{3})(\\))?([[:blank:]]*)?(\\d{3})([[:blank:]]*)?(\\d{4})";
17.23:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
bool valid(const smatch& m)
{
//若存在分隔符且匹配
if (m[2].matched)
//则后4位也要匹配
return m[3].matched;
else
return 1;
}
int main(int argc, char **argv)
{
string post_code = "(\\d{5})([-])?(\\d{4})?";
regex r(post_code);
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;
}
}
system("pause");
return 0;
}
17.24:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int main(int argc, char **argv)
{
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})";
regex r(phone);
smatch m;
string s;
string fmt = "$2.$5.$7";
while (getline(cin, s))
{
cout << regex_replace(s, r, fmt) << endl;
}
system("pause");
return 0;
}
17.25:
#include <iostream>
#include <sstream>
#include <string>
#include <regex>
using namespace std;
int main(int argc, char **argv)
{
using std::regex_constants::format_no_copy;
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})";
regex r(phone);
string s;
string fmt = "$2.$5.$7";
while (getline(cin, s))
{
smatch result;
regex_search(s, result, r); //先找到所有匹配的字符串,然后进行格式转换
if (!result.empty())
{
cout << result.format(fmt, format_no_copy) << endl;
}
else
cout << "没有匹配!" << endl;
}
system("pause");
return 0;
}
17.26:
#include <iostream>
#include <sstream>
#include <string>
#include <regex>
using namespace std;
int main(int argc, char **argv)
{
using std::regex_constants::format_no_copy;
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})";
regex r(phone);
string s;
string fmt = "$2.$5.$7";
while (getline(cin, s))
{
smatch result;
regex_search(s, result, r);
if (!result.empty())
{
string str = result.suffix();
cout << regex_replace(str,r,fmt,format_no_copy) << endl;
}
else
cout << "没有匹配!" << endl;
}
system("pause");
return 0;
}
17.27:
#include <iostream>
#include <sstream>
#include <string>
#include <regex>
using namespace std;
int main(int argc, char **argv)
{
using std::regex_constants::format_no_copy;
string post_code = "(\\d{5})(\\d{4})";
regex r(post_code);
string fmt = "$1-$2";
string s;
while (getline(cin, s))
{
cout << regex_replace(s, r, fmt, format_no_copy) << endl;
}
system("pause");
return 0;
}
17.28、17.29、17.30:
#include <iostream>
#include <sstream>
#include <string>
#include <regex>
#include <random>
using namespace std;
unsigned ran() //17.28
{
default_random_engine e;
uniform_int_distribution<unsigned> u;
return u(e);
}
unsigned ran(unsigned s) //17.29
{
default_random_engine e(s);
uniform_int_distribution<unsigned> u;
return u(e);
}
unsigned ran(unsigned s, unsigned min, unsigned max) //17.30
{
default_random_engine e(s);
uniform_int_distribution<unsigned> u(min, max);
return u(e);
}
int main(int argc, char **argv)
{
unsigned min, max;
cout << ran() << endl;
cout << ran(time(0)) << endl;
cin >> min >> max;
cout << ran(time(0), min, max);
system("pause");
return 0;
}
17.31:
如果在do循环内定义b和e,引擎返回的随机数序列相同
17.32:
在循环内定义resp,当while前面的循环体已退出,释放所有在循环体定义的对象,所以resp不存在
17.33:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <list>
#include <map>
#include <set>
#include <algorithm>
#include <random>
using namespace std;
map<string, string>
buildmap(ifstream &map_file)
{
map<string, string> trans_map; //保存转换规则
string key; //要转换的单词
string value; //替换后的内容
//读取第一个单词存入key中,行中剩余内容存入value
while (map_file >> key && getline(map_file, value))
{
if (value.size() > 1)
{
trans_map[key] = value.substr(1); //value为关键字之后的所有字符,包括与关键字之间的空格,所以令参数为1消去空格
}
else
throw runtime_error("no rule for " + key);
}
return trans_map;
}
string
transform(const string &s, const map<string, string> &m)
{
auto map_it = m.find(s);
//如果单词在转换规则之中
if (map_it != m.cend())
{
return map_it->second; //使用替换短语
}
else
return s; //如果单词不在转换规则中,则返回原单词
}
string
transform_random(const string &s, map<string, string> &m)
{
auto map_it = m.find(s);
//如果单词在转换规则之中
if (map_it != m.cend())
{
return m[s] + "!"; //使用替换短语
}
else
return s; //如果单词不在转换规则中,则返回原单词
}
void word_transform(ifstream &map_file, ifstream &input)
{
auto trans_map = buildmap(map_file); //保存转换规则
string text; //保存输入的每一行
static default_random_engine e;
static bernoulli_distribution b;
bool t;
while (getline(input, text)) //读取每一行输入
{
istringstream stream(text); //读取一行中的每个单词
string word;
bool firstword = true; //控制是否打印空格
while (stream >> word)
{
if (firstword) //如果读取的单词不为空,则之后打印一个空格
firstword = false;
else
cout << " ";
t = b(e);
if (!t)
cout << transform(word, trans_map); //将需要转换的单词转换
else
cout << transform_random(word, trans_map);
}
cout << endl;
}
}
int main(int argc, char**argv)
{
ifstream map_file("17.txt");
ifstream input("17.33.txt");
word_transform(map_file, input);
system("pause");
return 0;
}
17.34、7.35、17.36:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << unitbuf;//17.34
cout << boolalpha << (5 < 4 ? true : false) << noboolalpha << endl;
cout << showpos << showbase << hex << 1000 << " " << oct << 1000
<< " " << dec << 1000 << noshowbase << noshowpos << endl;
cout << uppercase << 3.14159 << " " << hex << 1000 << dec
<< nouppercase << endl;
cout << setfill('#') << setw(10) << internal << showpos << 1024
<< noshowpos << nounitbuf << ends << endl << flush;
cout << setw(10) << left << fixed << 3.14 << " " << right
<< scientific << 3.14 << endl;
cout << hexfloat << 3.14159 << endl;
cout << setprecision(3) << 3.14159 << endl;
cout << setbase(8) << 1000 << endl;
char ch;
cin >> noskipws;
while (cin >> ch && ch != 'q')
cout << ch;
cin >> skipws;
cout << endl;
cout << uppercase;//17.35
cout << "default format: " << 100 * sqrt(2.0) << '\n'
<< "scientific: " << scientific << 100 * sqrt(2.0) << '\n'
<< "fixed decimal: " << fixed << 100 * sqrt(2.0) << '\n'
<< "hexidecimal: " << uppercase << hexfloat << 100 * sqrt(2.0) << '\n'
<< "use defaults: " << defaultfloat << 100 * sqrt(2.0)
<< endl;
cout << setfill(' ');//17.36
cout << left << setw(20) << "default format:" << setw(25) << right << 100 * sqrt(2.0) << '\n'
<< left << setw(20) << "scientific:" << scientific << setw(25) << right << 100 * sqrt(2.0) << '\n'
<< left << setw(20) << "fixed decimal:" << setw(25) << fixed << right << 100 * sqrt(2.0) << '\n'
<< left << setw(20) << "hexidecimal:" << setw(25) << uppercase << hexfloat << right << 100 * sqrt(2.0) << '\n'
<< left << setw(20) << "use defaults:" << setw(25) << defaultfloat << right << 100 * sqrt(2.0)
<< "\n\n";
system("pause");
return 0;
}
17.37:
#include <iostream>
#include <iomanip>
#include <vector>
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
ifstream ifile("17.37.txt");
if (!ifile)
{
cout << "can't open the file" << endl;
exit(1);
}
char array[100];
do {
ifile.getline(array, 10);
cout << array << " ";
} while (ifile);
ifile.close();
system("pause");
return 0;
}
17.38:
#include <iostream>
#include <iomanip>
#include <vector>
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
ifstream ifile("17.37.txt");
if (!ifile)
{
cout << "can't open the file" << endl;
exit(1);
}
char array[100];
do {
ifile.getline(array, 100,' ');
cout << array << " ";
} while (ifile);
ifile.close();
system("pause");
return 0;
}
17.39:
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
fstream ifile("17.37.txt", fstream::ate | fstream::in | fstream::out); //以只读、只写和文件指针跳到文件尾的方式打开
if (!ifile)
{
cout << "Unable to open file" << endl;
return EXIT_FAILURE;
}
auto end_mark = ifile.tellg(); //记住原文件尾位置
ifile.seekg(0, fstream::beg); //重定位到文件开始
size_t cnt = 0; //字节数累加器
string line; //保存输入中的每行
//继续读取的条件,还未遇到错误且还存在读取数据
while (ifile && ifile.tellg () != end_mark && getline(ifile, line) )
{
cnt += line.size() + 1; //加1表示换行符
auto mark = ifile.tellg(); //记住读取位置
ifile.seekp(0, fstream::end); //将写标记移动到文件尾
ifile << cnt; //输出累计的长度
if (mark != end_mark) //如果不是最后一行,打印一个分隔符
ifile << " ";
ifile.seekg(mark); //恢复读位置
}
ifile.seekp(0, fstream::end); //定位到文件尾
ifile << "\n"; //在文件尾输出一个换行符
return 0;
system("pause");
return 0;
}