いくつかの標準ライブラリの使用:
1. タプルの型
1.1. タプルの定義と初期化
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"); //自动推断类型
タプルメンバーにアクセスする
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,获取指定元素的类型
関係演算子と等価演算子
为了使用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. タプルを使用して複数の値を返す
tuple<int, int> fun()
{
return make_tuple(1, 2);
}
auto d = fun();
auto first = get<0>(d);
2.ビットセットタイプ
2.1. ビットセットの定義と初期化 ビット
セットを符号なし値で初期化する
bitset<4> b(3);
bitset<128> b2(~0ULL); 前面64位补0,后面64位为1(~0ULL之后全为1)
文字列からビットセットを初期化する
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); //最后四个字符
2.2. ビットセット操作
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::]]+ 匹配一个或多个字母
正規表現オブジェクトのオプションを指定する
编写程序识别文件扩展名:
//一个或多个字母或数字字符后接一个.再接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++中的特殊字符,因此再加一个反斜杠
正規表現を指定または使用する際のエラー
一个正则表达式的语法是否正确是在运行时解析的。
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;
}
正規表現クラスと入力シーケンス タイプ
输入类型要匹配:处理什么输入序列类型,用什么类型的表达式类
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;
3.2. sregex_iterator を使用したRegex イテレーター型とのマッチング
查找字符串中的数字串
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;
}
マッチングデータの使用
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;
}
例如:匹配的一个子串:123789(str(0)),子串中第一个子表达式是123(str(1)),第二个子表达式是789(str(2))
str(0)是第一个子匹配位置,表示整个模式对应的匹配
データ検証用の部分式
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个数字
サブマッチ操作を使用する
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(); //分隔符必须匹配
}
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
マッチングとフォーマットを制御するフラグ
フォーマット フラグを使用する
regex r("[0-9]+");
string str("abc123aoe");
string fmt("BBB$1AAA")
cout<<regex_replace(str, r, fmt,format_no_copy); //只拷贝它替换的文本,结果:BBBAAA
4.乱数
C++ プログラムでは、ライブラリ関数 rand を使用しないでください。ただし、default_random_engine クラスと適切な部分クラス オブジェクトを使用する必要があります。
4.1. 乱数エンジンと分布
default_random_engine e;
cout << e() << endl;
配布タイプとエンジン
default_random_engine e(1); //设置随机种子
uniform_int_distribution<unsigned> u(0, 9); //设置范围
cout << u(e) << endl;
乱数エンジンと 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);
}
4.2. その他の乱数分布
ランダムな実数を生成する
default_random_engine e(1);
uniform_real_distribution<double> u2(0,1); //随机浮点数
cout << u(e) << endl;
分布にデフォルトの結果タイプを使用する
uniform_real_distribution<> u(0,1); //<>默认生成double值
uniform_int_distribution<> u(0, 9); //默认生成int值
一様に分布していない乱数を生成する
正态分布
default_random_engine e;
normal_distribution<> n(4, 1.5); //均值4,标准差1.5
n(e);
ベルヌーイ分布
default_random_engine e;
bernoulli_distribution b; //普通类
b(e); //默认是50/50的机会
bernoulli_distribution b(.55); 55/45的机会
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
制御入力フォーマット
空白符:空格符、制表符、换行符、换纸符、回车符
默认cin会忽略空白符
noskipws:设置cin读取空白符
输入:
a b c
d
默认输出:abcd
设置noskipws输出:
a b c
d
5.2. フォーマットされていない入出力操作
标准库还提供了一组底层操作,支持未格式化IO。这些操作允许我们将一个流当作一个无解释的字节序列来处理。
シングルバイト操作
char ch;
while(cin.get(ch))
cout.put(ch);
文字を入力ストリームに戻す
cin.peek();
cin.unget();
cin.putback(1);
入力操作から返された int 値
int i;
while (i = cin.get() != EOF)
{
cout.put(i);
}
マルチバイト操作
読み取られた文字数を特定する
5.3. ストリーム ランダム アクセス
随机IO本质上是依赖于系统的,为了理解如何使用这些特性,你必须查询系统文档。
标准库提供了一对函数来定位(seek)到流中给定的位置,已经告诉(tell)我们当前位置。
虽然标准库为所有流类型都定义了seek和tell函数,但它们是否会做有意义的事情依赖于流绑定到哪个设备。
在大多数系统中,cin、cout、cerr、clog的流不支持随机访问:当向cout直接输出数据时,类似向回跳十个
位置这种操作是没有意义的。对这些流我们可以调用seek、tell函数,但在运行时会出错,将流置于一个无效
状态。
由于istream和ostream类型通常不支持随机访问,剩余内容只适用于fstream和sstream类型。
関数を探して伝える
为了支持随机访问,IO类型维护了一个标记来确定下一个读写操作要在哪里进行。
提供了两个函数:
seek:将标记定位到一个给定位置
tell:告诉我们标记的当前位置
标准库定义了两队seek和tell函数,一对用于输入流(后缀g,获得数据),另一对用于输出流(后缀p,放置数据)
1つのマークのみ
流中只维护单一的标记:并不存在独立的读标记和写标记
移転タグ
seekg(new_pos); //绝对位置
seekg(offset,from); //相对位置
アクセストークン
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’