C Primer 第17章标准库特殊设施17.1 tuple 类型17.1.1 tuple 基础tuple 是 pair 的泛化 pair → 两个成员 tuple → 任意数量的成员每个成员可以是不同类型 头文件tuple// tuple_basic.cpp -- tuple基础 #include iostream #include tuple #include string #include vector int main() { using namespace std; // 创建 tuple tupleint, string, double t1(42, Hello, 3.14); auto t2 make_tuple(42, Hello, 3.14); // 推断类型 // C17 结构化绑定 auto [i, s, d] t2; cout i s d endl; // 访问 tuple 成员 // getN(t)获取第N个成员从0开始 cout get0(t1) endl; // 42 cout get1(t1) endl; // Hello cout get2(t1) endl; // 3.14 // 修改成员 get0(t1) 100; cout 修改后 get0(t1) endl; // tuple 的大小 cout 成员数 tuple_sizedecltype(t1)::value endl; // 3 // tuple 的成员类型 tuple_element1, decltype(t1)::type str World; cout str endl; // tuple 的比较 auto ta make_tuple(1, 2, 3); auto tb make_tuple(1, 2, 4); cout boolalpha; cout ta tb: (ta tb) endl; // true cout ta tb: (ta tb) endl; // false // tuple 的实际应用返回多个值 auto getMinMax [](const vectorint v) - tupleint, int, double { int minV *min_element(v.begin(), v.end()); int maxV *max_element(v.begin(), v.end()); double avg accumulate(v.begin(), v.end(), 0.0) / v.size(); return {minV, maxV, avg}; }; vectorint nums {3, 1, 4, 1, 5, 9, 2, 6}; auto [minV, maxV, avg] getMinMax(nums); cout min minV max maxV avg avg endl; return 0; }17.1.2 tuple 的高级用法// tuple_advanced.cpp -- tuple高级用法 #include iostream #include tuple #include string #include vector #include algorithm // 用 tuple 实现多键排序 struct Employee { string name; int dept; double salary; }; int main() { using namespace std; vectorEmployee employees { {张三, 2, 8000}, {李四, 1, 9000}, {王五, 2, 7500}, {赵六, 1, 8500}, {钱七, 3, 10000} }; // 按部门升序同部门按薪资降序排序 sort(employees.begin(), employees.end(), [](const Employee a, const Employee b) { return make_tuple(a.dept, -a.salary) make_tuple(b.dept, -b.salary); }); cout 排序结果 endl; for (const auto e : employees) cout 部门 e.dept e.name $ e.salary endl; // tuple 拼接 auto t1 make_tuple(1, 2, 3); auto t2 make_tuple(a, b); auto t3 tuple_cat(t1, t2); // 拼接两个tuple cout \ntuple_cat结果 endl; cout get0(t3) get1(t3) get2(t3) get3(t3) get4(t3) endl; // tie解包 tuple int a, b, c; tie(a, b, c) make_tuple(10, 20, 30); cout \ntie解包 a b c endl; // 忽略某些成员 tie(a, ignore, c) make_tuple(100, 200, 300); cout 忽略中间 a c endl; return 0; }17.2 bitset 类型// bitset_demo.cpp -- bitset详解 #include iostream #include bitset #include string int main() { using namespace std; // 创建 bitset bitset8 b1; // 8位全0 bitset8 b2(0b10110100); // 从整数初始化 bitset8 b3(10110100); // 从字符串初始化 bitset8 b4(0xFF); // 255 11111111 cout b1 b1 endl; // 00000000 cout b2 b2 endl; // 10110100 cout b3 b3 endl; // 10110100 cout b4 b4 endl; // 11111111 // 访问位 cout \n访问位 endl; cout b2[0] b2[0] endl; // 最低位0 cout b2[2] b2[2] endl; // 1 cout b2[7] b2[7] endl; // 最高位1 // test()检查指定位有边界检查 cout b2.test(2) boolalpha b2.test(2) endl; // 修改位 bitset8 b b2; b.set(0); // 将位0置1 b.reset(7); // 将位7置0 b.flip(4); // 翻转位4 cout \n修改后 b endl; b.set(); // 所有位置1 cout 全1 b endl; b.reset(); // 所有位置0 cout 全0 b endl; b.flip(); // 翻转所有位 cout 翻转 b endl; // 位运算 bitset8 x(10110100); bitset8 y(01101100); cout \n位运算 endl; cout x y (x y) endl; // 按位与 cout x | y (x | y) endl; // 按位或 cout x ^ y (x ^ y) endl; // 按位异或 cout ~x (~x) endl; // 按位取反 cout x 2 (x 2) endl; // 左移 cout x 2 (x 2) endl; // 右移 // 统计和转换 cout \n统计 endl; cout count(1的个数) x.count() endl; cout size(总位数) x.size() endl; cout any(有1) x.any() endl; cout all(全1) x.all() endl; cout none(全0) x.none() endl; // 转换 cout \n转换 endl; cout to_ulong x.to_ulong() endl; cout to_ullong x.to_ullong() endl; cout to_string x.to_string() endl; // 实际应用权限管理 cout \n 权限管理 endl; enum Permission { READ 0, WRITE 1, EXECUTE 2, ADMIN 3 }; bitset4 userPerm; userPerm.set(READ); userPerm.set(WRITE); cout 用户权限 userPerm endl; cout 有读权限 userPerm.test(READ) endl; cout 有执行权限 userPerm.test(EXECUTE) endl; // 添加权限 userPerm.set(EXECUTE); cout 添加执行权限后 userPerm endl; // 删除权限 userPerm.reset(WRITE); cout 删除写权限后 userPerm endl; return 0; }17.3 正则表达式// regex_demo.cpp -- 正则表达式 #include iostream #include regex #include string #include vector int main() { using namespace std; // 基本匹配 cout 基本匹配 endl; string pattern R(\d{3}-\d{4}-\d{4}); // 手机号格式 regex re(pattern); string text 联系方式138-1234-5678 或 010-12345678; // regex_search在字符串中搜索 smatch match; if (regex_search(text, match, re)) cout 找到手机号 match[0] endl; // regex_match整个字符串匹配 string phone 138-1234-5678; cout 是手机号 boolalpha regex_match(phone, re) endl; // 查找所有匹配 cout \n 查找所有匹配 endl; string emails 联系 aliceexample.com 或 bobtest.org 获取帮助; regex emailRe(R([a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,})); sregex_iterator it(emails.begin(), emails.end(), emailRe); sregex_iterator end; while (it ! end) { cout 邮箱 (*it)[0] endl; it; } // 捕获组 cout \n 捕获组 endl; string date 2024-01-15; regex dateRe(R((\d{4})-(\d{2})-(\d{2}))); smatch dateMatch; if (regex_match(date, dateMatch, dateRe)) { cout 完整匹配 dateMatch[0] endl; cout 年 dateMatch[1] endl; cout 月 dateMatch[2] endl; cout 日 dateMatch[3] endl; } // 替换 cout \n 替换 endl; string text2 Hello World Hello C; regex helloRe(Hello); // regex_replace替换所有匹配 string result regex_replace(text2, helloRe, Hi); cout 替换后 result endl; // 只替换第一个 string result2 regex_replace(text2, helloRe, Hi, regex_constants::format_first_only); cout 只替换第一个 result2 endl; // 分割字符串 cout \n 分割字符串 endl; string csv apple,banana,,cherry,date; regex sepRe(,); sregex_token_iterator tokIt(csv.begin(), csv.end(), sepRe, -1); sregex_token_iterator tokEnd; while (tokIt ! tokEnd) { cout \ *tokIt \ endl; tokIt; } // 实际应用验证输入 cout \n 输入验证 endl; auto validate [](const string input, const string pattern, const string name) { regex re(pattern); bool valid regex_match(input, re); cout name \ input \ boolalpha valid endl; return valid; }; // 验证邮箱 validate(userexample.com, R([a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}), 邮箱); validate(invalid-email, R([a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}), 邮箱); // 验证IP地址 validate(192.168.1.1, R((\d{1,3}\.){3}\d{1,3}), IP地址); validate(256.0.0.1, R((\d{1,3}\.){3}\d{1,3}), IP地址); return 0; }17.4 随机数// random_demo.cpp -- 随机数 #include iostream #include random #include vector #include map #include iomanip #include algorithm int main() { using namespace std; // 随机数引擎 // 默认随机数引擎 default_random_engine engine; // 使用随机设备作为种子真随机 random_device rd; default_random_engine engine2(rd()); // 使用时间作为种子 default_random_engine engine3(time(nullptr)); // 均匀分布 cout 均匀分布 endl; // 整数均匀分布 [1, 6]模拟骰子 uniform_int_distributionint dice(1, 6); cout 骰子; for (int i 0; i 10; i) cout dice(engine2) ; cout endl; // 浮点均匀分布 [0, 1) uniform_real_distributiondouble prob(0.0, 1.0); cout 概率; for (int i 0; i 5; i) cout fixed setprecision(3) prob(engine2) ; cout endl; // 正态分布 cout \n 正态分布 endl; normal_distributiondouble normal(0.0, 1.0); // 均值0标准差1 // 统计分布 mapint, int hist; for (int i 0; i 10000; i) { int bucket static_castint(round(normal(engine2))); hist[bucket]; } cout 正态分布直方图 endl; for (auto [val, cnt] : hist) { if (val -3 val 3) { cout setw(3) val | ; cout string(cnt / 100, *) endl; } } // 其他分布 cout \n 其他分布 endl; // 伯努利分布成功概率0.7 bernoulli_distribution bern(0.7); int successes 0; for (int i 0; i 1000; i) if (bern(engine2)) successes; cout 伯努利(p0.7)1000次成功 successes endl; // 泊松分布平均值4 poisson_distributionint poisson(4.0); cout 泊松分布(λ4); for (int i 0; i 10; i) cout poisson(engine2) ; cout endl; // 随机打乱 cout \n 随机打乱 endl; vectorint v {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; shuffle(v.begin(), v.end(), engine2); cout 打乱后; for (int x : v) cout x ; cout endl; // 实际应用随机抽样 cout \n 随机抽样 endl; vectorstring names {Alice, Bob, Carol, David, Eve, Frank, Grace, Henry}; // 随机选3个 shuffle(names.begin(), names.end(), engine2); cout 随机选3人; for (int i 0; i 3; i) cout names[i] ; cout endl; return 0; }17.5 IO 库再探17.5.1 格式化输入输出// io_format.cpp -- 格式化IO #include iostream #include iomanip #include sstream #include string int main() { using namespace std; // 整数格式 cout 整数格式 endl; int n 255; cout 十进制 dec n endl; cout 八进制 oct n endl; cout 十六进制 hex n endl; cout 十六进制大写 uppercase hex n endl; cout dec nouppercase; // 恢复 // 显示进制前缀 cout showbase; cout 带前缀十进制 dec n endl; cout 带前缀八进制 oct n endl; cout 带前缀十六进制 hex n endl; cout noshowbase dec; // 显示正号 cout showpos 42 -42 noshowpos endl; // 浮点格式 cout \n 浮点格式 endl; double pi 3.14159265358979; cout 默认 pi endl; cout fixed fixed pi endl; cout scientific scientific pi endl; cout defaultfloat; // 精度 for (int p 1; p 8; p) cout precision( p ) setprecision(p) pi endl; cout setprecision(6); // 恢复默认 // 宽度和对齐 cout \n 宽度对齐 endl; cout setw(10) 右对齐 | endl; cout left setw(10) 左对齐 | endl; cout right; // 填充字符 cout setfill(0) setw(8) 42 endl; // 00000042 cout setfill(*) setw(10) Hi endl; // ********Hi cout setfill( ); // 恢复 // 格式化表格 cout \n 格式化表格 endl; cout fixed setprecision(2); cout left setw(12) 商品 right setw(8) 数量 setw(10) 单价 setw(10) 小计 endl; cout string(40, -) endl; struct Item { string name; int qty; double price; }; Item items[] {{苹果, 5, 3.50}, {香蕉, 12, 1.80}, {橙子, 8, 4.20}}; double total 0; for (const auto item : items) { double subtotal item.qty * item.price; total subtotal; cout left setw(12) item.name right setw(8) item.qty setw(10) item.price setw(10) subtotal endl; } cout string(40, -) endl; cout right setw(30) 合计 setw(10) total endl; return 0; }17.5.2 未格式化 IO// unformatted_io.cpp -- 未格式化IO #include iostream #include fstream #include string int main() { using namespace std; // 单字节操作 cout 单字节操作 endl; // get()读取单个字符含空白 char ch; cout 输入字符; cin.get(ch); cout 读取到 ch endl; // peek()查看但不读取 char next cin.peek(); cout 下一个字符 next endl; // putback()放回字符 cin.putback(ch); // unget()撤销最后一次读取 // cin.unget(); // 多字节操作 cout \n 多字节操作 endl; // read()读取指定字节数 char buf[10]; cin.read(buf, 5); buf[5] \0; cout read(5) buf endl; // gcount()上次读取的字节数 cout gcount cin.gcount() endl; // 文件定位 cout \n 文件定位 endl; // 写入测试文件 { ofstream out(test.bin, ios::binary); out Hello, World!; } // 读取并定位 ifstream in(test.bin, ios::binary); // tellg()获取当前位置 cout 初始位置 in.tellg() endl; // seekg()设置读取位置 in.seekg(7); // 从头移动7字节 cout 移动到7后 in.tellg() endl; char c; in.get(c); cout 读取到 c endl; // W // 从末尾定位 in.seekg(-6, ios::end); string rest; getline(in, rest); cout 末尾前6字节 rest endl; return 0; }17.6 综合示例日志分析系统// log_analyzer.cpp -- 综合示例日志分析系统 #include iostream #include fstream #include sstream #include string #include regex #include map #include vector #include tuple #include algorithm #include iomanip #include random // 日志条目 struct LogEntry { string timestamp; string level; string module; string message; }; class LogAnalyzer { private: vectorLogEntry entries_; // 日志格式[2024-01-15 10:30:45] [INFO] [Module] Message regex logPattern_{ R(\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(\w)\] \[(\w)\] (.)) }; public: // 解析日志文件 bool parseFile(const string filename) { ifstream file(filename); if (!file) return false; string line; while (getline(file, line)) { smatch match; if (regex_match(line, match, logPattern_)) { entries_.push_back({ match[1], match[2], match[3], match[4] }); } } return true; } // 解析字符串 void parseString(const string logs) { istringstream iss(logs); string line; while (getline(iss, line)) { smatch match; if (regex_match(line, match, logPattern_)) { entries_.push_back({ match[1], match[2], match[3], match[4] }); } } } // 按级别统计 mapstring, int countByLevel() const { mapstring, int counts; for (const auto e : entries_) counts[e.level]; return counts; } // 按模块统计 mapstring, int countByModule() const { mapstring, int counts; for (const auto e : entries_) counts[e.module]; return counts; } // 搜索包含关键词的日志 vectorLogEntry search(const string keyword) const { vectorLogEntry results; regex kw(keyword, regex_constants::icase); for (const auto e : entries_) if (regex_search(e.message, kw)) results.push_back(e); return results; } // 获取错误日志 vectorLogEntry getErrors() const { vectorLogEntry errors; for (const auto e : entries_) if (e.level ERROR || e.level CRITICAL) errors.push_back(e); return errors; } // 生成报告 void generateReport(ostream os) const { os \n string(60, ) endl; os 日志分析报告 endl; os string(60, ) endl; os \n总条目数 entries_.size() endl; // 级别统计 os \n 按级别统计 endl; for (const auto [level, count] : countByLevel()) os setw(10) level : count 条 endl; // 模块统计 os \n 按模块统计 endl; for (const auto [module, count] : countByModule()) os setw(10) module : count 条 endl; // 错误日志 auto errors getErrors(); if (!errors.empty()) { os \n 错误日志 errors.size() 条 endl; for (const auto e : errors) os [ e.timestamp ] [ e.level ] [ e.module ] e.message endl; } } }; // 生成测试日志 string generateTestLogs() { default_random_engine engine(42); uniform_int_distributionint levelDist(0, 3); uniform_int_distributionint moduleDist(0, 2); vectorstring levels {DEBUG, INFO, WARNING, ERROR}; vectorstring modules {Auth, Database, Network}; vectorstring messages { 用户登录成功, 数据库连接建立, 网络请求超时, 认证失败密码错误, 查询执行完成, 连接池已满, 用户注销, 事务提交成功, DNS解析失败 }; uniform_int_distributionint msgDist(0, messages.size() - 1); ostringstream oss; for (int i 0; i 20; i) { int h 10 i / 4, m (i * 15) % 60, s i * 3 % 60; oss [2024-01-15 setfill(0) setw(2) h : setw(2) m : setw(2) s ] [ levels[levelDist(engine)] ] [ modules[moduleDist(engine)] ] messages[msgDist(engine)] \n; } return oss.str(); } int main() { using namespace std; LogAnalyzer analyzer; // 解析测试日志 string logs generateTestLogs(); cout 原始日志 endl; cout logs; analyzer.parseString(logs); // 生成报告 analyzer.generateReport(cout); // 搜索 cout \n 搜索\失败\ endl; auto results analyzer.search(失败); for (const auto e : results) cout [ e.level ] e.message endl; return 0; } 第17章知识点总结知识点核心要点tuplemake_tuple创建getN访问C17结构化绑定解包tuple_sizetuple_sizeT::value获取成员数量tuple_elementtuple_elementN,T::type获取第N个成员的类型tietie(a,b,c) t解包tupleignore忽略某个成员tuple_cat拼接多个tuplebitset固定大小的位集合支持位运算set/reset/flip/testbitset 统计count()1的个数、any()、all()、none()regexregex_match全匹配、regex_search搜索、regex_replace替换smatch存储匹配结果[0]是完整匹配[1]起是捕获组sregex_iterator遍历所有匹配结果随机数引擎default_random_engine用random_device或时间作种子随机数分布uniform_int_distribution、uniform_real_distribution、normal_distribution格式化IOsetw/setprecision/fixed/scientific/left/right/setfill未格式化IOget/peek/putback/read/gcount/seekg/tellg
C++ Primer 第17章:标准库特殊设施
C Primer 第17章标准库特殊设施17.1 tuple 类型17.1.1 tuple 基础tuple 是 pair 的泛化 pair → 两个成员 tuple → 任意数量的成员每个成员可以是不同类型 头文件tuple// tuple_basic.cpp -- tuple基础 #include iostream #include tuple #include string #include vector int main() { using namespace std; // 创建 tuple tupleint, string, double t1(42, Hello, 3.14); auto t2 make_tuple(42, Hello, 3.14); // 推断类型 // C17 结构化绑定 auto [i, s, d] t2; cout i s d endl; // 访问 tuple 成员 // getN(t)获取第N个成员从0开始 cout get0(t1) endl; // 42 cout get1(t1) endl; // Hello cout get2(t1) endl; // 3.14 // 修改成员 get0(t1) 100; cout 修改后 get0(t1) endl; // tuple 的大小 cout 成员数 tuple_sizedecltype(t1)::value endl; // 3 // tuple 的成员类型 tuple_element1, decltype(t1)::type str World; cout str endl; // tuple 的比较 auto ta make_tuple(1, 2, 3); auto tb make_tuple(1, 2, 4); cout boolalpha; cout ta tb: (ta tb) endl; // true cout ta tb: (ta tb) endl; // false // tuple 的实际应用返回多个值 auto getMinMax [](const vectorint v) - tupleint, int, double { int minV *min_element(v.begin(), v.end()); int maxV *max_element(v.begin(), v.end()); double avg accumulate(v.begin(), v.end(), 0.0) / v.size(); return {minV, maxV, avg}; }; vectorint nums {3, 1, 4, 1, 5, 9, 2, 6}; auto [minV, maxV, avg] getMinMax(nums); cout min minV max maxV avg avg endl; return 0; }17.1.2 tuple 的高级用法// tuple_advanced.cpp -- tuple高级用法 #include iostream #include tuple #include string #include vector #include algorithm // 用 tuple 实现多键排序 struct Employee { string name; int dept; double salary; }; int main() { using namespace std; vectorEmployee employees { {张三, 2, 8000}, {李四, 1, 9000}, {王五, 2, 7500}, {赵六, 1, 8500}, {钱七, 3, 10000} }; // 按部门升序同部门按薪资降序排序 sort(employees.begin(), employees.end(), [](const Employee a, const Employee b) { return make_tuple(a.dept, -a.salary) make_tuple(b.dept, -b.salary); }); cout 排序结果 endl; for (const auto e : employees) cout 部门 e.dept e.name $ e.salary endl; // tuple 拼接 auto t1 make_tuple(1, 2, 3); auto t2 make_tuple(a, b); auto t3 tuple_cat(t1, t2); // 拼接两个tuple cout \ntuple_cat结果 endl; cout get0(t3) get1(t3) get2(t3) get3(t3) get4(t3) endl; // tie解包 tuple int a, b, c; tie(a, b, c) make_tuple(10, 20, 30); cout \ntie解包 a b c endl; // 忽略某些成员 tie(a, ignore, c) make_tuple(100, 200, 300); cout 忽略中间 a c endl; return 0; }17.2 bitset 类型// bitset_demo.cpp -- bitset详解 #include iostream #include bitset #include string int main() { using namespace std; // 创建 bitset bitset8 b1; // 8位全0 bitset8 b2(0b10110100); // 从整数初始化 bitset8 b3(10110100); // 从字符串初始化 bitset8 b4(0xFF); // 255 11111111 cout b1 b1 endl; // 00000000 cout b2 b2 endl; // 10110100 cout b3 b3 endl; // 10110100 cout b4 b4 endl; // 11111111 // 访问位 cout \n访问位 endl; cout b2[0] b2[0] endl; // 最低位0 cout b2[2] b2[2] endl; // 1 cout b2[7] b2[7] endl; // 最高位1 // test()检查指定位有边界检查 cout b2.test(2) boolalpha b2.test(2) endl; // 修改位 bitset8 b b2; b.set(0); // 将位0置1 b.reset(7); // 将位7置0 b.flip(4); // 翻转位4 cout \n修改后 b endl; b.set(); // 所有位置1 cout 全1 b endl; b.reset(); // 所有位置0 cout 全0 b endl; b.flip(); // 翻转所有位 cout 翻转 b endl; // 位运算 bitset8 x(10110100); bitset8 y(01101100); cout \n位运算 endl; cout x y (x y) endl; // 按位与 cout x | y (x | y) endl; // 按位或 cout x ^ y (x ^ y) endl; // 按位异或 cout ~x (~x) endl; // 按位取反 cout x 2 (x 2) endl; // 左移 cout x 2 (x 2) endl; // 右移 // 统计和转换 cout \n统计 endl; cout count(1的个数) x.count() endl; cout size(总位数) x.size() endl; cout any(有1) x.any() endl; cout all(全1) x.all() endl; cout none(全0) x.none() endl; // 转换 cout \n转换 endl; cout to_ulong x.to_ulong() endl; cout to_ullong x.to_ullong() endl; cout to_string x.to_string() endl; // 实际应用权限管理 cout \n 权限管理 endl; enum Permission { READ 0, WRITE 1, EXECUTE 2, ADMIN 3 }; bitset4 userPerm; userPerm.set(READ); userPerm.set(WRITE); cout 用户权限 userPerm endl; cout 有读权限 userPerm.test(READ) endl; cout 有执行权限 userPerm.test(EXECUTE) endl; // 添加权限 userPerm.set(EXECUTE); cout 添加执行权限后 userPerm endl; // 删除权限 userPerm.reset(WRITE); cout 删除写权限后 userPerm endl; return 0; }17.3 正则表达式// regex_demo.cpp -- 正则表达式 #include iostream #include regex #include string #include vector int main() { using namespace std; // 基本匹配 cout 基本匹配 endl; string pattern R(\d{3}-\d{4}-\d{4}); // 手机号格式 regex re(pattern); string text 联系方式138-1234-5678 或 010-12345678; // regex_search在字符串中搜索 smatch match; if (regex_search(text, match, re)) cout 找到手机号 match[0] endl; // regex_match整个字符串匹配 string phone 138-1234-5678; cout 是手机号 boolalpha regex_match(phone, re) endl; // 查找所有匹配 cout \n 查找所有匹配 endl; string emails 联系 aliceexample.com 或 bobtest.org 获取帮助; regex emailRe(R([a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,})); sregex_iterator it(emails.begin(), emails.end(), emailRe); sregex_iterator end; while (it ! end) { cout 邮箱 (*it)[0] endl; it; } // 捕获组 cout \n 捕获组 endl; string date 2024-01-15; regex dateRe(R((\d{4})-(\d{2})-(\d{2}))); smatch dateMatch; if (regex_match(date, dateMatch, dateRe)) { cout 完整匹配 dateMatch[0] endl; cout 年 dateMatch[1] endl; cout 月 dateMatch[2] endl; cout 日 dateMatch[3] endl; } // 替换 cout \n 替换 endl; string text2 Hello World Hello C; regex helloRe(Hello); // regex_replace替换所有匹配 string result regex_replace(text2, helloRe, Hi); cout 替换后 result endl; // 只替换第一个 string result2 regex_replace(text2, helloRe, Hi, regex_constants::format_first_only); cout 只替换第一个 result2 endl; // 分割字符串 cout \n 分割字符串 endl; string csv apple,banana,,cherry,date; regex sepRe(,); sregex_token_iterator tokIt(csv.begin(), csv.end(), sepRe, -1); sregex_token_iterator tokEnd; while (tokIt ! tokEnd) { cout \ *tokIt \ endl; tokIt; } // 实际应用验证输入 cout \n 输入验证 endl; auto validate [](const string input, const string pattern, const string name) { regex re(pattern); bool valid regex_match(input, re); cout name \ input \ boolalpha valid endl; return valid; }; // 验证邮箱 validate(userexample.com, R([a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}), 邮箱); validate(invalid-email, R([a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}), 邮箱); // 验证IP地址 validate(192.168.1.1, R((\d{1,3}\.){3}\d{1,3}), IP地址); validate(256.0.0.1, R((\d{1,3}\.){3}\d{1,3}), IP地址); return 0; }17.4 随机数// random_demo.cpp -- 随机数 #include iostream #include random #include vector #include map #include iomanip #include algorithm int main() { using namespace std; // 随机数引擎 // 默认随机数引擎 default_random_engine engine; // 使用随机设备作为种子真随机 random_device rd; default_random_engine engine2(rd()); // 使用时间作为种子 default_random_engine engine3(time(nullptr)); // 均匀分布 cout 均匀分布 endl; // 整数均匀分布 [1, 6]模拟骰子 uniform_int_distributionint dice(1, 6); cout 骰子; for (int i 0; i 10; i) cout dice(engine2) ; cout endl; // 浮点均匀分布 [0, 1) uniform_real_distributiondouble prob(0.0, 1.0); cout 概率; for (int i 0; i 5; i) cout fixed setprecision(3) prob(engine2) ; cout endl; // 正态分布 cout \n 正态分布 endl; normal_distributiondouble normal(0.0, 1.0); // 均值0标准差1 // 统计分布 mapint, int hist; for (int i 0; i 10000; i) { int bucket static_castint(round(normal(engine2))); hist[bucket]; } cout 正态分布直方图 endl; for (auto [val, cnt] : hist) { if (val -3 val 3) { cout setw(3) val | ; cout string(cnt / 100, *) endl; } } // 其他分布 cout \n 其他分布 endl; // 伯努利分布成功概率0.7 bernoulli_distribution bern(0.7); int successes 0; for (int i 0; i 1000; i) if (bern(engine2)) successes; cout 伯努利(p0.7)1000次成功 successes endl; // 泊松分布平均值4 poisson_distributionint poisson(4.0); cout 泊松分布(λ4); for (int i 0; i 10; i) cout poisson(engine2) ; cout endl; // 随机打乱 cout \n 随机打乱 endl; vectorint v {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; shuffle(v.begin(), v.end(), engine2); cout 打乱后; for (int x : v) cout x ; cout endl; // 实际应用随机抽样 cout \n 随机抽样 endl; vectorstring names {Alice, Bob, Carol, David, Eve, Frank, Grace, Henry}; // 随机选3个 shuffle(names.begin(), names.end(), engine2); cout 随机选3人; for (int i 0; i 3; i) cout names[i] ; cout endl; return 0; }17.5 IO 库再探17.5.1 格式化输入输出// io_format.cpp -- 格式化IO #include iostream #include iomanip #include sstream #include string int main() { using namespace std; // 整数格式 cout 整数格式 endl; int n 255; cout 十进制 dec n endl; cout 八进制 oct n endl; cout 十六进制 hex n endl; cout 十六进制大写 uppercase hex n endl; cout dec nouppercase; // 恢复 // 显示进制前缀 cout showbase; cout 带前缀十进制 dec n endl; cout 带前缀八进制 oct n endl; cout 带前缀十六进制 hex n endl; cout noshowbase dec; // 显示正号 cout showpos 42 -42 noshowpos endl; // 浮点格式 cout \n 浮点格式 endl; double pi 3.14159265358979; cout 默认 pi endl; cout fixed fixed pi endl; cout scientific scientific pi endl; cout defaultfloat; // 精度 for (int p 1; p 8; p) cout precision( p ) setprecision(p) pi endl; cout setprecision(6); // 恢复默认 // 宽度和对齐 cout \n 宽度对齐 endl; cout setw(10) 右对齐 | endl; cout left setw(10) 左对齐 | endl; cout right; // 填充字符 cout setfill(0) setw(8) 42 endl; // 00000042 cout setfill(*) setw(10) Hi endl; // ********Hi cout setfill( ); // 恢复 // 格式化表格 cout \n 格式化表格 endl; cout fixed setprecision(2); cout left setw(12) 商品 right setw(8) 数量 setw(10) 单价 setw(10) 小计 endl; cout string(40, -) endl; struct Item { string name; int qty; double price; }; Item items[] {{苹果, 5, 3.50}, {香蕉, 12, 1.80}, {橙子, 8, 4.20}}; double total 0; for (const auto item : items) { double subtotal item.qty * item.price; total subtotal; cout left setw(12) item.name right setw(8) item.qty setw(10) item.price setw(10) subtotal endl; } cout string(40, -) endl; cout right setw(30) 合计 setw(10) total endl; return 0; }17.5.2 未格式化 IO// unformatted_io.cpp -- 未格式化IO #include iostream #include fstream #include string int main() { using namespace std; // 单字节操作 cout 单字节操作 endl; // get()读取单个字符含空白 char ch; cout 输入字符; cin.get(ch); cout 读取到 ch endl; // peek()查看但不读取 char next cin.peek(); cout 下一个字符 next endl; // putback()放回字符 cin.putback(ch); // unget()撤销最后一次读取 // cin.unget(); // 多字节操作 cout \n 多字节操作 endl; // read()读取指定字节数 char buf[10]; cin.read(buf, 5); buf[5] \0; cout read(5) buf endl; // gcount()上次读取的字节数 cout gcount cin.gcount() endl; // 文件定位 cout \n 文件定位 endl; // 写入测试文件 { ofstream out(test.bin, ios::binary); out Hello, World!; } // 读取并定位 ifstream in(test.bin, ios::binary); // tellg()获取当前位置 cout 初始位置 in.tellg() endl; // seekg()设置读取位置 in.seekg(7); // 从头移动7字节 cout 移动到7后 in.tellg() endl; char c; in.get(c); cout 读取到 c endl; // W // 从末尾定位 in.seekg(-6, ios::end); string rest; getline(in, rest); cout 末尾前6字节 rest endl; return 0; }17.6 综合示例日志分析系统// log_analyzer.cpp -- 综合示例日志分析系统 #include iostream #include fstream #include sstream #include string #include regex #include map #include vector #include tuple #include algorithm #include iomanip #include random // 日志条目 struct LogEntry { string timestamp; string level; string module; string message; }; class LogAnalyzer { private: vectorLogEntry entries_; // 日志格式[2024-01-15 10:30:45] [INFO] [Module] Message regex logPattern_{ R(\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] \[(\w)\] \[(\w)\] (.)) }; public: // 解析日志文件 bool parseFile(const string filename) { ifstream file(filename); if (!file) return false; string line; while (getline(file, line)) { smatch match; if (regex_match(line, match, logPattern_)) { entries_.push_back({ match[1], match[2], match[3], match[4] }); } } return true; } // 解析字符串 void parseString(const string logs) { istringstream iss(logs); string line; while (getline(iss, line)) { smatch match; if (regex_match(line, match, logPattern_)) { entries_.push_back({ match[1], match[2], match[3], match[4] }); } } } // 按级别统计 mapstring, int countByLevel() const { mapstring, int counts; for (const auto e : entries_) counts[e.level]; return counts; } // 按模块统计 mapstring, int countByModule() const { mapstring, int counts; for (const auto e : entries_) counts[e.module]; return counts; } // 搜索包含关键词的日志 vectorLogEntry search(const string keyword) const { vectorLogEntry results; regex kw(keyword, regex_constants::icase); for (const auto e : entries_) if (regex_search(e.message, kw)) results.push_back(e); return results; } // 获取错误日志 vectorLogEntry getErrors() const { vectorLogEntry errors; for (const auto e : entries_) if (e.level ERROR || e.level CRITICAL) errors.push_back(e); return errors; } // 生成报告 void generateReport(ostream os) const { os \n string(60, ) endl; os 日志分析报告 endl; os string(60, ) endl; os \n总条目数 entries_.size() endl; // 级别统计 os \n 按级别统计 endl; for (const auto [level, count] : countByLevel()) os setw(10) level : count 条 endl; // 模块统计 os \n 按模块统计 endl; for (const auto [module, count] : countByModule()) os setw(10) module : count 条 endl; // 错误日志 auto errors getErrors(); if (!errors.empty()) { os \n 错误日志 errors.size() 条 endl; for (const auto e : errors) os [ e.timestamp ] [ e.level ] [ e.module ] e.message endl; } } }; // 生成测试日志 string generateTestLogs() { default_random_engine engine(42); uniform_int_distributionint levelDist(0, 3); uniform_int_distributionint moduleDist(0, 2); vectorstring levels {DEBUG, INFO, WARNING, ERROR}; vectorstring modules {Auth, Database, Network}; vectorstring messages { 用户登录成功, 数据库连接建立, 网络请求超时, 认证失败密码错误, 查询执行完成, 连接池已满, 用户注销, 事务提交成功, DNS解析失败 }; uniform_int_distributionint msgDist(0, messages.size() - 1); ostringstream oss; for (int i 0; i 20; i) { int h 10 i / 4, m (i * 15) % 60, s i * 3 % 60; oss [2024-01-15 setfill(0) setw(2) h : setw(2) m : setw(2) s ] [ levels[levelDist(engine)] ] [ modules[moduleDist(engine)] ] messages[msgDist(engine)] \n; } return oss.str(); } int main() { using namespace std; LogAnalyzer analyzer; // 解析测试日志 string logs generateTestLogs(); cout 原始日志 endl; cout logs; analyzer.parseString(logs); // 生成报告 analyzer.generateReport(cout); // 搜索 cout \n 搜索\失败\ endl; auto results analyzer.search(失败); for (const auto e : results) cout [ e.level ] e.message endl; return 0; } 第17章知识点总结知识点核心要点tuplemake_tuple创建getN访问C17结构化绑定解包tuple_sizetuple_sizeT::value获取成员数量tuple_elementtuple_elementN,T::type获取第N个成员的类型tietie(a,b,c) t解包tupleignore忽略某个成员tuple_cat拼接多个tuplebitset固定大小的位集合支持位运算set/reset/flip/testbitset 统计count()1的个数、any()、all()、none()regexregex_match全匹配、regex_search搜索、regex_replace替换smatch存储匹配结果[0]是完整匹配[1]起是捕获组sregex_iterator遍历所有匹配结果随机数引擎default_random_engine用random_device或时间作种子随机数分布uniform_int_distribution、uniform_real_distribution、normal_distribution格式化IOsetw/setprecision/fixed/scientific/left/right/setfill未格式化IOget/peek/putback/read/gcount/seekg/tellg