系列文章目录
文章目录
前言
从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{1,2,3}; //正确,直接初始化
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对象
随机数
分布( 随机数引擎 )