17 C++ tuple、bitset、正则表达式、随机数、IO库

系列文章目录



前言

从1998年至2011年,标准库部分的篇幅增加了两倍以上。本片介绍4个较为通用的标准库设施:tuple、bitset、随机数生成、正则表达式。此外还会介绍一些附加的IO库功能:格式控制、未格式化IO、随机访问。
标准库占据了标准文本近2/3的篇幅。


提示:以下是本篇文章正文内容,下面案例可供参考

tuple类型 tuple

<tuple>
在这里插入图片描述
可以将tuple看作一个’快速而随意’的数据结构

定义和初始化tuple

tuple<size_t, size_t, size_t> threeD;	//三个成员都设为0
tuple<string, vector<double>, int, list<int>> someVal("cons", {1.3, 3.15}, 21, {3,4,5});

tuple<size_t, size_t, size_t> threeD = {1,2,3}; //❌
tuple<size_t, size_t, size_t> threeD{123};	//正确,直接初始化

auto item = make_tuple("sdf", 3, 20.9);

访问tuple的成员

auto book  = get<0>(item); 
get<2>(item) *= 0.8;

typedef decltype(item) trans;	//trans是item的类型
//返回trans类型对象中成员的数量
size_t sz = tuple_size<trans>::value; 返回3
//cnt的类型与item中第二个成员相同
tuple_element<1, trans>::type cnt = get<1>(item);	//cnt是一个int

使用tuple返回多个值

与python的tuple有些像,与python list更像。

bitset类型 bitset

<bitset>
处理位运算

定义与初始化

在这里插入图片描述
在这里插入图片描述
从一个string初始化bitset

bitset<32> bitvec4("1100");
string str("1111010110101001");
bitset<32> bitvec5(str, 5, 4);			 //从str[5]开始的四个二进制位
bitset<32> bitvec6(str, str.size()-4);   //使用最后四个字符

bitset操作

在这里插入图片描述提取bitset的值

unsigned long ulong = bitvec3.to_ulong();
cout << "ulong = " << ulong << endl;

bitset IO运算符

正则表达式 regex

regular expression,一种描述字符序列的方法
在这里插入图片描述
在这里插入图片描述

使用正则表达式库

“i除非在c之后,否则必须在e之前”

									//找查不在字符c之后的字符串ei
string pattern("[^c]ei");
									//我们需要包含pattern的整个单词
pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*" ;
regex r(pattern);								//构造一个用于找查模式的regex
smatch results;									//定义一个对象保存搜索结果
									// 定义一个string保存与模式匹配和不匹配的文本
string test_str = "receipt freind theif receive";
									// 用r在test_str中找查与pattern匹配的子串
if (regex_search(test_str, results, r))	  		//如果有匹配子串
	cout << results.str() << endl;

在这里插入图片描述

//一个或多个字母或数字字符后接一个‘.’再接“cpp”或“cxx”或“cc”
regex r("[[:alnum:]]+\\.(cpp|cxx|cc)$", regex::icase);
smatch results;
string filename;
while (cin >> filename)
	if (regex_search(filename, results, r))
		cout << results.str() << endl;

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

try{
	//❌:alnum漏掉了右括号,构造函数会抛出异常
	regex r("[[:alnum:]+\\.(cpp|cxx|cc)$", regex::icase);
}catch (regex_error e){
	cout << e.what() << "\ncode: " << e.code() << endl;
}

正则表达式错误类型

在这里插入图片描述
e.code()返回错误编号,从0开始

正则表达式所表示的“程序”在运行时而非编译时编译。
正则表达式类和输入序列类型

regex r("[[:alnum:]]+\\.(cpp|cxx|cc)$", regex::icase);
smatch results;	//将匹配string输入序列,而不是char*
if (regex_search("myfile.cc", results, r)) //❌错误:输入为char*
	cout << results.str() << endl;

正则表达式库类
在这里插入图片描述

匹配与Regex迭代器类型

sregex_iterator操作
在这里插入图片描述
在这里插入图片描述

//找查前一个字符不是c的字符串ei
string pattern("[^c]ei");
//我们想要包含pattern的单词的全部内容
pattern = "[[:alpha:]]*" + pattern + "[[:alpha:]]*";
regex r(pattern, regex::icase);
//它将反复调用regex_search来寻找文件中的所有匹配
for (sregex_iterator it(file.begin(), file.end(), r), end_it;
	 it != end_it; ++it )
	 cout << it->str() << endl; //匹配的单词

使用匹配数据

for (sregex_iterator it(file.begin(), file.end(), r), end_it;
	 it != end_it; ++it)
	auto pos = it->prefix().length();	//前缀大小
	pos = pos > 40 ? pos%40 : pos;		//最多40个字符
	cout << it->prefix().str().substr(pos)	//前缀的最后一部分
		 << "\n\t\t>>>" << it->str() << " <<<\n"	//匹配的单词
		 << it->suffix().str().substr(0, 40)		//后缀的第一部分
		 << endl;

it->prefix()返回 ssub_match对象,该对象有名为str(字符串)和length(长度)的成员
在这里插入图片描述
在这里插入图片描述

使用子表达式

regex r("([[:alnum:]]+)\\.(cpp|cxx|cc)", regex::icase);
// ([[:alnum:]]+) 匹配一个或多个字符的序列
// (cpp|cxx|cc)   匹配文件扩展名
if (regex_search(filename, results, r))
	cout << results.str(1) << endl;		//打印第一个子表达式
//results.str(0/1/2)  xx.cpp/ xxx/ cpp

子表达式用于数据验证
ECMAScript正则表达式语言的特性:
在这里插入图片描述

//整个正则表达式包含七个子表达式: ( ddd )分隔符ddd 分隔符 dddd
//子表达式1、3、4和6时可选的;2、5和7保存号码
"(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})";
string phone = "(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})";
regex r(phone);		//regex对象,用于查找我们的模式
smatch m;
string s;
//从输入文件中读取每条记录
//*it 为 smatch it->str()为 ssub_match
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;
}

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();
}

pattern有7个子表达式,每个smatch对象会包含8个ssub_match元素。位置[0]为整个匹配;元素[1]…[7]表示每个对应的子表达式。如果一个子表达式时完整匹配的一部分,则其对应的ssub_match对象的matched成员为true
在这里插入图片描述

使用regex_replace

在这里插入图片描述
$后跟子表达式的索引号来表示一个特定的子表达式

string fmt = "$2.$5.$7";	//将号码格式改为ddd.ddd.dddd

regex r(phone);
string number = "(908) 555-1800";
// regex_replace函数找查并转换所有匹配子串,输出转换后的所有string
cout << regex_replace(number, r, fmt) << endl;

用来控制匹配和格式的标志
using namespace std::regex_constants::format_no_copy;

using std::regex_constants::format_no_copy;
using namespace std::regex_constants;

在这里插入图片描述
使用格式标志

//只生成电话号码:使用新的格式字符串
string fmt2 = "$2.$5.$7 ";
//通知regex_replace只拷贝它替换的文本
cout << regex_replace(s, r, fmt2, format_no_copy) << endl;

随机数 random、ctime

<random>
随机数引擎类random-number engines   生成unsigned随机数序列
随机数分布类random-number distribution  生成指定类型、在给定范围内的、服从特定概率分布的随机数

随机数引擎和分布

default_random_engin e;  //e为default_random_engin类的实例
cout << e() << endl;	 //default_random_engin类重载了调用运算符

随机数引擎操作
在这里插入图片描述
分布类型和引擎

//生成[0,9]之间均匀分布的随机数
uniform_int_distribution<unsigned> u(0,9);
default_random_engin e;
for (size_t i = 0; i<10; ++i){
	//将u作为随机数源
	//每个调用返回在指定范围并服从均匀分布的值
	cout << u(e) << " ";
}

随机数发生器:分布和引擎对象的组合

//几乎肯定是生成随机整数vector的错误方法
//每次调用这个函数都会生成相同的100个数
vector<unsigned> bad_randVec(){
	default_random_engin e;
	uniform_int_distribution<unsigned> u(0,9);
	vector<unsigned> ret;
	for (int i = 0; i<100; ++i)
		ret.push_back(u(e));
	return ret;
}

//返回一个vector,包含100个均匀分布的随机数
vector<unsigned> good_randVec(){
	//由于希望引擎和分布对象保持状态,因此应该将它们
	//定义为static的,从而每次调用都生成新的数
	static default_random_engine e;
	static uniform_int_distribution<unsigned> u(0,9);
	vector<unsigned> ret;
	for (int i=0; i<100; ++i)
		ret.push_back(u(e));
	return ret;
}

//返回一个vector,包含100个均匀分布的随机数
//程序每次运行都不相同
vector<unsigned> good_randVec(){
	static default_random_engine e(time(nullptr));
	static uniform_int_distribution<unsigned> u(0,9);
	vector<unsigned> ret;
	for (int i=0; i<100; ++i)
		ret.push_back(u(e));
	return ret;
}

将time(nullptr)用作seed,当两次调用时间<1s时,就不适用了

其他随机数分布

生成随机实数

default_random_engine e;
//[0, 1]
uniform_real_distribution<double> u(0,1); //uniform_real_distribution<> u(0,1)默认double
for (size_t i = 0; i<10; ++i)
	cout << u(e) << " ";

在这里插入图片描述
生成非均匀分布的随机数

default_random_engine e;		 //生成“随机整数”
normal_distribution<> n(4, 1.5); //均值4,标准差1.5
vector<unsigned> vals(9);		 //9个元素均为0
for (size_t j = 0; j!=vals.size(); ++j){
	unsigned v = lround(n(e));
	if (v < vals.size())
		++vals[v];
}
for (size_t j = 0; j!=vals.size(); ++j)
	cout << j << ": " << string(vals[j], '*') <<endl;

bernoulli_distribution类

string resp;
default_random_engine e;
bernoulli_distribution b;
do{
	bool first = b(e);
	cout << (first ? "We go first": "You get to go first") <<endl;
	cout << (play(first))? "sory, you lost" : "congrats, you won") << endl;
	cout << "play again? Enter 'yes' or 'no' " << endl; 
}while (cin >> resp && resp[0] == 'y');

IO库

格式控制、未格式化IO、随机访问

格式化输入输出 iomanip

控制布尔的格式
boolalpha
noboolalpha

cout << true << boolalpha << false << noboolalpha << true << endl;

指定整型值的进制
hex, oct, dec

cout << hex << 16;

uppercase
showbase // 当打印整型值时显示进制
noshowbase
控制浮点数的格式

cout.precision()
cout.precision(12)
cout.setprecision(3)

在这里插入图片描述
在这里插入图片描述
输出补白
在这里插入图片描述

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

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

流随机访问

在这里插入图片描述


总结

tuple是一个模板,允许将多个不同类型到的成员捆绑成单一对象。
bitset允许定义指定大小的二进制位集合。
正则表达式库提供了一组类和函数:regex类管理用于某种正则表达式语言编写的正则表达式。
随机数库有一组随机数引擎类和分布类组成。

正则表达式:

string pattern = "xxx";
regex r(pattern); 创建regex对象,匹配模式
smatch 为容器类
sregex_iterator调用regex_search,返回迭代器。该迭代器解引用后得到smatch对象
smatch.prefex()/.suffix()得到ssub_match对象

随机数
分布( 随机数引擎 )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值