• C++ Primer学习笔记-----第十七章:标准款特殊设施


    几个标准库的使用:

    1.tuple类型
    在这里插入图片描述
    1.1.定义和初始化tuple

    tuple<int,int> t1;		//默认值初始化
    tuple<int,string,vector<int>> t2(1,"a",{1,2});		//直接初始化
    tuple<int, int> t3{ 1,2 };
    auto t4 = make_tuple(1, "a");	//自动推断类型
    
    • 1
    • 2
    • 3
    • 4

    访问tuple的成员

    tuple<int,string> t(1,"a");
    auto item = get<0>(t);	//第一个元素
    get<1>(t) = "b";
    
    typedef decltype(t) v;
    size_t sz = tuple_size<v>::value;			//tuple中成员数量,返回2
    tuple_element<1,v>::type cnt = get<1>(t);	//cnt是一个int,获取指定元素的类型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    关系和相等运算符

    为了使用tuple的相等或不等运算符,对每对成员使用==运算符必须都是合法的;
    为了使用关系运算符,对每对成员使用<必须都是合法的。
    tuple<int,int> t1(1,2);
    tuple<int,int> t2(1,2);
    bool b = (t1==t2);		
    b = (t1<t2);
    由于tuple定义了<==运算符,可以将tuple序列传递给算法,并且可以在无序容器中将tuple作为关键字类型。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1.2.使用tuple返回多个值

    tuple<int, int> fun()
    {
    	return make_tuple(1, 2);
    }
    
    auto d = fun();
    auto first = get<0>(d);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.bitset类型

    2.1.定义和初始化bitset
    在这里插入图片描述
    用unsigned值初始化bitset

    bitset<4> b(3);
    bitset<128> b2(~0ULL);	前面64位补0,后面64位为1~0ULL之后全为1
    • 1
    • 2

    从一个string初始化bitset

    bitset<8> bitvec("1100");	//2、3两位为1,剩余两位为0;
    位值:0000 1100
    bitset中的下标从低位到高位,顺序和字符串中的下标顺序是反的。
    
    string s("1111111100000000");
    bitset<32> b(s,5,4);	//从s[5]开始的四个二进制位
    bitset<32> b2(s,s.size()-4);	//最后四个字符
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    2.2.bitset操作

    在这里插入图片描述
    3.正则表达式

    在这里插入图片描述
    在这里插入图片描述
    3.1.使用正则表达式库

    string s("[0-9]+");
    regex r(s);
    smatch result;
    string str = "b123de4567";
    if(regex_search(str, result, r))
    	cout << result.str();
    
    [[::alpha::]]	匹配任意字母
    [[::alpha::]]*	匹配零个或多个字母
    [[::alpha::]]+	匹配一个或多个字母
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    指定regex对象的选项
    在这里插入图片描述

    编写程序识别文件扩展名:
    //一个或多个字母或数字字符后接一个.再接cpp或cxx或cc
    string p = "[[:alnum:]]+\\.(cpp|cxx|cc)$";
    regex r(p, regex::icase);
    smatch result;
    string fileName;
    while (cin >> fileName)
    	if (regex_search(fileName, result, r))
    		cout << result.str() << endl;
    
    由于.是通配符,所以需要加反斜杠,反斜杠也是C++中的特殊字符,因此再加一个反斜杠
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    指定或使用正则表达式时的错误

    一个正则表达式的语法是否正确是在运行时解析的。
    
    regex_error成员:
    what():错误信息
    code():错误类型对应的数值编码
    
    try
    {
    	regex r("[[:alnum:]]+\\.(cpp|cxx|cc)$",regex::icase);
    }
    catch(regex_error e)
    {
    	cout<<e.what()<<endl;
    	cout<<e.code()<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述
    在这里插入图片描述
    正则表达式类和输入序列类型
    在这里插入图片描述

    输入类型要匹配:处理什么输入序列类型,用什么类型的表达式类
    string p = "[[:alnum:]]+.(cpp|cxx|cc)$";
    regex r(p, regex::icase);
    smatch result;
    string fileName;
    while (cin >> fileName)
    	if (regex_search(fileName, result, r))	//这里的result只能是smatch,不能是cmatch等其他类型
    		cout << result.str() << endl;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3.2.匹配与Regex迭代器类型
    在这里插入图片描述在这里插入图片描述
    使用sregex_iterator

    查找字符串中的数字串
    string p = "[0-9]+";
    regex r(p);
    smatch result;
    string str = "abc123efo345op";
    sregex_iterator end;
    for (sregex_iterator it(str.begin(), str.end(), r); it != end; ++it)
    {
    	cout << it->str() << endl;
    	cout <<"前子串"<<it->prefix().str() << "长度" << it->prefix().length() << endl;
    	cout <<"后子串"<<it->suffix().str() << "长度" << it->suffix().length() << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    使用匹配数据
    在这里插入图片描述
    3.3.使用子表达式

    string p = "([0-4]+)([5-9]+)";	//一个小括号代表一个子表达式,两个子表达式
    regex r(p);
    smatch result;
    string str = "abc123789efo345op";
    sregex_iterator end;
    for (sregex_iterator it(str.begin(), str.end(), r); it != end; ++it)
    {
    	cout << it->str() <<" First: "<<it->str(1) << " Second: "<<it->str(2) <<endl;
    }
    例如:匹配的一个子串:123789str(0)),子串中第一个子表达式是123str(1)),第二个子表达式是789str(2)str(0)是第一个子匹配位置,表示整个模式对应的匹配
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    子表达式用于数据验证

    string p = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})";
    regex r(p);
    smatch result;
    string str = "abcd(123).123.1324";
    sregex_iterator end;
    for (sregex_iterator it(str.begin(), str.end(), r); it != end; ++it)
    {
    	cout << it->str() << endl;	//匹配(123).123.1324
    	valid(*it);	//验证
    }
    (\\()?  		:匹配(
    (\\d{3})		:匹配3个数字
    (\\))?			:匹配)
    ([-. ])?		:匹配-.空格分隔符
    (\\d{4})"		:匹配4个数字
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用子匹配操作
    在这里插入图片描述

    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();	//分隔符必须匹配
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.4.使用regex_replace

    在这里插入图片描述
    替换输入序列的一部分

    regex r("[0-9]+");	
    string str("abc123aoe");
    string fmt("BBB$1AAA");					//$1表示第一个子表达式,在第一个子表达式前面置BBB,后面置AAA
    cout<<regex_replace(str, r, fmt);		//结果:abcBBBAAAaoe
    
    • 1
    • 2
    • 3
    • 4

    用来控制匹配和格式的标志
    在这里插入图片描述

    使用格式标志

    regex r("[0-9]+");	
    string str("abc123aoe");
    string fmt("BBB$1AAA")
    cout<<regex_replace(str, r, fmt,format_no_copy);	//只拷贝它替换的文本,结果:BBBAAA
    
    • 1
    • 2
    • 3
    • 4

    4.随机数

    C++程序不应该使用库函数rand,应使用default_random_engine类和恰当的分部类对象。

    4.1.随机数引擎和分布
    在这里插入图片描述

    default_random_engine e;
    cout << e() << endl;		
    
    • 1
    • 2

    分布类型和引擎

    default_random_engine e(1);						//设置随机种子
    uniform_int_distribution<unsigned> u(0, 9);		//设置范围
    cout << u(e) << endl;
    
    • 1
    • 2
    • 3

    比较随机数引擎和rand函数

    //下面的函数每次返回的值都是一样的
    unsigned getRandom(unsigned min, unsigned max, unsigned seed = 0)
    {
    	default_random_engine e(seed);
    	uniform_int_distribution<unsigned> u(min, max);
    	return u(e);
    }
    
    静态对象会保存状态,所以会不一样
    unsigned getRandom(unsigned min, unsigned max, unsigned seed = 0)
    {
    	static default_random_engine e(seed);
    	static uniform_int_distribution<unsigned> u(min, max);
    	return u(e);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.2.其他随机数分布

    生成随机实数

    default_random_engine e(1);
    uniform_real_distribution<double> u2(0,1);	//随机浮点数
    cout << u(e) << endl;
    
    • 1
    • 2
    • 3

    在这里插入图片描述
    使用分布的默认结果类型

    uniform_real_distribution<> u(0,1);		//<>默认生成double值
    uniform_int_distribution<> u(0, 9);		//默认生成int值
    
    • 1
    • 2

    生成非均匀分布的随机数

    正态分布
    default_random_engine e;
    normal_distribution<> n(4, 1.5);	//均值4,标准差1.5
    n(e);
    
    • 1
    • 2
    • 3
    • 4

    伯努利分布

    default_random_engine e;
    bernoulli_distribution b;	//普通类
    b(e);		//默认是50/50的机会
    
    bernoulli_distribution b(.55);		55/45的机会
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.IO库在探

    5.1.格式化输入与输出
    在这里插入图片描述在这里插入图片描述
    输出补白
    在这里插入图片描述

    cout << left;	//左对齐
    cout << "i:" << setw(6) << "AAA" << endl;		i:AAA
    cout << right;	//右对齐
    cout << "i:" << setw(6) << "AAA" << endl;		i:   AAA
    cout << internal;	//用空白填充
    cout << "i:" << setw(6) << "AAA" << endl;		i:   AAA
    cout << setfill('#');	//用字符填充
    cout << "i:" << setw(6) << "AAA" << endl;		i:###AAA
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    控制输入格式

    空白符:空格符、制表符、换行符、换纸符、回车符
    默认cin会忽略空白符	
    noskipws:设置cin读取空白符
    
    输入:
    a b  c
    d
    默认输出:abcd
    设置noskipws输出:
    a b  c
    d
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5.2.未格式化的输入/输出操作

    标准库还提供了一组底层操作,支持未格式化IO。这些操作允许我们将一个流当作一个无解释的字节序列来处理。
    
    • 1

    单字节操作
    在这里插入图片描述

    char ch;
    while(cin.get(ch))
    	cout.put(ch);
    
    • 1
    • 2
    • 3

    将字符放回输入流

    cin.peek();
    cin.unget();
    cin.putback(1);
    
    • 1
    • 2
    • 3

    从输入操作返回的int值

    int i;
    while (i = cin.get() != EOF)
    {
    	cout.put(i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    多字节操作
    在这里插入图片描述在这里插入图片描述

    确定读取了多少个字符

    在这里插入图片描述

    5.3.流随机访问

    随机IO本质上是依赖于系统的,为了理解如何使用这些特性,你必须查询系统文档。
    标准库提供了一对函数来定位(seek)到流中给定的位置,已经告诉(tell)我们当前位置。
    虽然标准库为所有流类型都定义了seek和tell函数,但它们是否会做有意义的事情依赖于流绑定到哪个设备。
    在大多数系统中,cin、cout、cerr、clog的流不支持随机访问:当向cout直接输出数据时,类似向回跳十个
    位置这种操作是没有意义的。对这些流我们可以调用seek、tell函数,但在运行时会出错,将流置于一个无效
    状态。
    
    由于istream和ostream类型通常不支持随机访问,剩余内容只适用于fstream和sstream类型。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    seek和tell函数

    为了支持随机访问,IO类型维护了一个标记来确定下一个读写操作要在哪里进行。
    提供了两个函数:
    seek:将标记定位到一个给定位置
    tell:告诉我们标记的当前位置
    标准库定义了两队seek和tell函数,一对用于输入流(后缀g,获得数据),另一对用于输出流(后缀p,放置数据)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    只有一个标记

    流中只维护单一的标记:并不存在独立的读标记和写标记
    
    • 1

    重定位标记

    seekg(new_pos);			//绝对位置
    seekg(offset,from);		//相对位置
    
    • 1
    • 2

    访问标记

    tellg();
    fstream::beg
    sstream::beg
    
    例如:
    fstream fs("path",fstream::ate|fstream::in|fstream::out);	//定位到文件尾
    auto endPos= fs.tellg();		//获取文件尾位置
    fs.seek(0,fstream::beg);	//从定位到文件开始位置
    fs.seek(endPos)				//定位到文件尾
    fs<<"abc";					
    fs<<"abc\n";				//输入5个字符,\n添加了两个字符,最后一个字符是‘\n’
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    MySQL基础必会,简单易懂
    在 Visual Studio 2022 (Visual C++ 17) 中使用 Visual Leak Detector
    【SpringMVC】文件上传与下载、JREBEL使用
    SAP 采购订单免费标识自动勾选的判断依据
    基于指数分布优化的BP神经网络(分类应用) - 附代码
    shell脚本执行jps时:-bash: jps: command not found
    【Linux】在Xilinx平台上实现UVC Gadget(2)- 解决dwc3驱动bug
    Hotspot启动原理(一)
    4.查询用户的累计消费金额及VIP等级
    uniapp实战项目 (仿知识星球App) - - 编译项目并安装到手机上
  • 原文地址:https://blog.csdn.net/weixin_41155760/article/details/126142324