C/C++基礎----標準庫幾個工具庫tuple,bitset,正則表示式,隨機數,IO庫
tuple
tuple可以有任意多個成員 預設初始化,值初始化 建構函式是explicit,必須直接初始化 make_tuple(v1,v2,…,vn) get<i> (t) 返回第i個數據成員的引用,t是左值則返回左值引用,右值則返回右值引用 tuple_size<tupleType>::value 表示成員的數量 tuple_element<i,tupleType>::type 表示給定tuple型別中指定成員的型別 為了使用關係運算符,每對成員使用運算子比較都是合法的。 如果tuple定義了<和==,則可以將tuple序列傳遞給演算法,並且可以在無序容器中講tuple作為關鍵字。
bitset
使得位運算的使用更加容易,並且能夠處理超過最長整型型別大小的位集合。 具有固定的大小,定義時必須給出。編號從0開始是低位。 預設構造,constexpr,每一位均為0 直接構造,將unsigned long long值u的低n位拷貝,如果不足n位高位被置0 bitset<n> b(s, pos, m, zero, one) string s的pos位置開始拷貝m個字元,s只能包含zero和one。pos預設0,m預設string::npos,zero預設’0’ 也可以從指向的字元陣列中拷貝字元,如果未提供m則必須是c風格字串。如果提供了m從pos開始至少有m個zero或one 字串中下標最小的字元對應高位。
函式 | 操作 |
---|---|
b.any() | b中是否存在置位 |
b.all() | 是否所有位都置位 |
b.none() | 是否不存在置位的位 |
b.count() | 位置的位數 |
b.size() | constexpr 返回b中的位數 |
b.test(pos) | 檢查pos位置是否置位 |
b.set(pos,v) | 將pos位置設定為v,v預設true |
b.set() | 所有位置位 |
b.reset(pos) | 復位pos處 |
b.reset() | 所有位復位 |
b.flip(pos) | 改變pos處位的狀態 |
b.flip() | 改變所有位的狀態 |
b[pos] | 訪問pos處的位;如果b是const,返回的是bool |
b.to_ulong() | 只能往大了轉,否則丟擲overflow_error |
b.to_ullong() | |
b.to_string(zero,one) 返回一個string | |
os<<b | |
is>>b | 當下一個不是1或0時,或已經讀了size位時停止 |
正則表示式
- regex 正則表示式類
regex_match 判定整個輸入序列與表示式是否匹配
regex_search 判定是否有子串與表示式匹配,找到一個就停止
regrex_replace 使用給定格式替換一個表示式
sregex_iterator 迭代器介面卡,呼叫search來遍歷一個string中所有的子串
smatch 容器類,儲存搜尋的結果
ssub_match string中匹配的子表示式的結果
regrex_search引數 (seq, m, r, mft) 在seq序列中查詢regrex物件r中的正則表示式,匹配的結果儲存在m,mft是一個可選的regex_constants::match_flag_type值,會影響匹配過程
regex_match引數 (seq, r, mft)
regex r(re, f) re是一個正則表示式,f是標誌,預設為ECMAScript
標誌定義在regex和regex_constants::syntax_option_type中
icase 在匹配過程中忽略大小寫
nosubs 不儲存匹配的子表示式
optimize 執行速度優先於構造速度
ECMAScript 使用ECMA-262指定的語法
basic 使用POSIX基本的正則表示式語法
extended POSIX擴充套件
awk POSIX版本的awk語言的語法
grep POSIX版本的grep語法
egrep POSIX版本的egrep語法
- 特殊字元
[^c]任意不是c的字元
ECMAScript中[[:alpha:]]表示匹配任意字母
+表示一個或多個
*表示零個或多個
string pattern(“[^c]ei”);
pattern = “[[:alpha:]]*” + pattern + “[[:alpha:]]*”;
regex r(“[[:alpha:]]+\\.(cpp|cxx|cc)$”, regex::icase);
字元點.通常匹配任意字元
可以在前面放一個反斜線來去掉其特殊意義
又因為反斜線也是C++中的特殊字元,所以需要再使用一個反斜線得到普通反斜線字元
- 使用
一個正則表示式的語法是否正確是在執行時解析的。
如果存在錯誤,會丟擲regex_error
catch (regex_error e)
{cout<<e.what()<<”\ncode: ”<<e.code()<<endl;}
構造或者賦值一個regex物件是非常耗時的,最小化開銷應該避免建立不必要的regex。
特別是在迴圈中使用的話,應該在外部建立。
- RE庫類
string regex、smatch、ssub_match和sregex_iterator
const char* regex、cmatch、csub_match和cregex_iterator
wstring wregex、wsmatch、wssub_match和wsregex_iterator
const wchar_t* wregex、wcmatch、wcsub_match和wcregex_iterator
迭代器在構造時會執行一次search,後面每遞增一次從當前位置開始呼叫search
sregex_iterator it(b, e, r);
sregex_iterator end; //空的表示尾後迭代器
除了得到匹配的結果,我們還能夠得到匹配結果的更多細節資訊。
it->str()
it->prefix().str() xxxeixxx it->suffix().str()
- smatch操作
(同樣適用於cmatch、wsmatch、wcmatch和對應的csub_match、wsub_match和wcsub_match)
操作 | 描述 |
---|---|
m.ready() | 已經通過搜尋設定了m則返回true |
m.size() | 如匹配失敗,則返回0;否則返回匹配子表示式的個數 |
m.empty() | size為0 則true |
m.prefix() | 一個ssub_match物件,表示當前匹配之前的序列 |
m.suffix() | 之後的序列 |
m.format(…) | 生成格式化輸出 |
以下n預設0且必須小於m.size().索引0表示整個匹配 | |
m.length(n) | 匹配結果中第n個子表示式 |
mposition(n) | 第n個子表示式距序列開始的距離 |
m.str(n) | 第n個子表示式的string |
m[n] | 對應第n個子表示式的ssub_match物件 |
m.begin() m.end() | 表示m中sun_match元素範圍的迭代器 |
m.cbegin() m.cend() |
- 使用子表示式
通常用括號表示子表示式
regex r(“[[:alpha:]]+\\.(cpp|cxx|cc)$”, regex::icase);
如上面的例子在search之後
results.str(1)表示第一個子表示式,即檔名部分
- ECMAScript正則表示式的一些特性
\{d}表示單個數字,\{d}{n}表示n個數字(如\{d}{3})
方括號中的字元集合表示匹配這些字元中任意一個(如[-. ]匹配短橫、點或一個空格)。點在括號中沒有特殊含義
後接一個’?’的元件是可選的( \{d}{3}[-. ]?\{d}{4} )
反斜線表示一個字元本身而不是其特殊意義。由於括號是特殊字元,所以需要加\(和\)
C++中反斜線是特殊字元,所以每次出現的地方都要兩個\\
“(\\()?(\\d{3})(\\))?([-. ])?(\\d{3})([-. ]?)(\\d{4})”
(\\()? 表示區號部分可選的左括號
(\\d{3}) 表示區號
(\\))? 表示區號部分可選的右括號
([-. ])? 表示可選的分隔符
(\\d{3}) 表示3位號碼
([-. ]?) 表示可選的分隔符
(\\d{4}) 表示號碼的最後4位
- 子匹配操作
操作 | 描述 |
---|---|
matched | 指出ssub_match是否匹配了 |
first | 指向匹配序列首元素的迭代器 |
second | 指向匹配序列尾後位置的迭代器 |
length() | 子匹配序列的大小 |
str() | 返回一個包含輸入中匹配部分的string,未匹配則空串 |
s=ssub | ssub_match物件ssub轉換為string物件 |
- 當希望查詢並替換時,可以使用regex_replace
m.format(dest, fmt,mft)
m.format(fmt, mft)
使用格式化字串fmt生成格式化輸出。第一個版本寫入迭代器dest指向的目的位置。fmt可以是string,也可以是表示字元陣列範圍的一對指標。
第二個版本返回一個string,fmt可以是string,也可以是一個指向空字元結尾的指標。
mft預設format_default
regex_replace(dest, seq, r, fmt, mft)
regex_replace(seq, r, fmt, mft)
遍歷seq查詢匹配的子串。seq既可以是string也可以是c風格字串。fmt既可以是string也可以是c風格字串。
mft預設match_default
- 使用$後跟子表示式的索引號來表示一個特定的子表示式
string fmt=”$2.$5.$7”;//將號碼格式改為ddd.ddd.dddd
regex r(phone);
string number = “(905) 555-1800”;
cout<<regex_replace(number, r, fmt)<<endl;
- 匹配和格式化標誌 regex_constants::match_flag_type
標誌 | 描述 |
---|---|
match_default | 同format_dafault |
match_not_bol | 不將首字元作為行首處理 |
match_not_eol | 不將尾字元作為行尾處理 |
match_not_bow | 不將首字元作為單詞首處理 |
match_not_eow | 不將尾字元作為單詞尾處理 |
match_any | 如果存在多餘一個匹配,則可返回任意一個匹配 |
match_not_null | 不匹配任何空序列 |
match_continuous | 匹配必須從輸入的首字元開始 |
match_prev_avial | 輸入序列包含第一個匹配之前的內容 |
format_default | 使用ECMAScript規則替換字串 |
format_sed | 用POSIX sed規則替換 |
format_no_copy | 不輸出輸入序列中未匹配的部分 |
format_first_only | 只替換子表示式的第一次出現 |
隨機數
以前都依賴rand函式來生成,此函式生成均勻分佈的偽隨機整數。每個數的範圍都在0到一個系統相關最大值之間。
問題:需要不同範圍的隨機數,需要隨機浮點數,需要非均勻分佈的數。程式設計師為解決這些問題而試圖轉換的過程常常會引入非隨機性。
標準庫提供了隨機數引擎類和隨機數分佈類來解決這些問題。
引擎類生成unsigned隨機數序列,分佈類使用引擎類生成指定型別的、在給定範圍內、服從特定概率分佈的隨機數。
C++程式不應該使用rand,而應該使用default_random_engine類和恰當的分佈類物件
可以通過呼叫引擎物件來生成原始隨機數
default_random_engine e; cout<<e()<<endl;
引擎可以用整型值s作為種子 Engine e(s); e.seed(s);//重置引擎狀態
e.discard(u) 將引擎推進u步
原始隨機數通常不能直接使用,需要轉換。所以用到分佈類
uniform_int_distribution<unsigned> u(0, 9);//0到9之間(包含)均勻分佈隨機數
default_random_engine e;
cout<<u(e)<<endl;
分佈類也是函式物件類,可以呼叫,接收一個引擎物件作為引數。注意是引擎物件本身,而不是其生成的值。
當我們說隨機數發生器時,是指的引擎物件和分佈物件的組合。
引擎生成整數在一個系統定義的範圍內(我的系統0到4294967295)
rand生成範圍0到RAND_MAX之間(我的系統0到32767)
每次返回相同的數值序列,在除錯時非常有用,但是設計時必須考慮。
如是區域性的可以定義為static,則每次呼叫都會推進。
種子是一個數值,引擎可以從序列中一個新位置重新開始生成隨機數。
最常用的是呼叫系統時間time(在標頭檔案<ctime>中),time接受單個指標引數,指向用於寫入時間的資料結構。如果指標為空,則簡單的返回時間。
因為time返回的是以秒計的時間,只適用於生成種子間隔秒級甚至更長的應用。
d.reset()//重置d的狀態,不依賴與已經生成的值
uniform_real_distribution<double> u(0, 1); //生成均勻分佈的隨機實數,同樣包含
非均勻分佈隨機數
標準庫定義20中分佈型別,見附錄
正態 normal_distribution<> n(4, 1.5);
伯努利 bernoulli_ distribution b;//非模板,返回bool,true的概率為常數,預設0.5
IO庫再探
格式控制、未格式化IO、隨機訪問
操縱符改變流的狀態,通常改變後對後面所有IO都生效。不需要特殊格式時儘快恢復。
輸出控制:控制數值輸出形式,控制補白的數量和位置
浮點數預設:6位數字精度列印;沒有小數部分則不列印小數點根據浮點數的值列印成定點十進位制或科學計數法
呼叫IO物件的precision成員或setprecision操縱符來改變精度
precision接收一個int,將精度設定成此值,並返回舊精度值。或者不接受引數,返回當前精度值。setprecision接收一個引數設定精度。
scientific、fixed或hexfloat後,精度值時控制的小數點後位數,而預設是總的位數。
setw指定下一個數字或字串值的最小空間
setfill可以指定一個字元替代預設的空格
setprecision設定精度
setbase設定整數輸出進位制
- 輸入控制
預設:忽略空白符(空格、製表符、換行符、換紙符、回車符)
操縱符noskipws,讀取空白符,skipws恢復
未格式化IO , 允許我們將一個流當做無解釋的位元組序列來處理
單位元組低層IO操作
操作 | 描述 |
---|---|
is.get(ch) | 從is讀取下一個位元組存入字元ch中,返回is |
os.put(ch) | 將字元ch輸出到os,返回os |
is.get() | 將is的下一個位元組作為一個int返回 |
is.putback(ch) | 將字元ch放回is,返回is |
is.unget() | 將is向後移動一個位元組,返回is |
is.peek() | 將下一個位元組作為int返回,但是不從流中刪除它 |
- 標準庫保證我們可以退回最多一個值
返回int值可以返回檔案尾標記,char範圍內的字元都已經佔了。標準庫使用負值表示檔案尾。<cstdio>中定義了名為EOF的const來檢測返回的是否是檔案尾。
int ch;
while((ch = cin.get() !=EOF)
cout.put(ch);
- 多位元組底層IO操作
操作 | 描述 |
---|---|
is.get(sink, size, delim) | 從is中讀取最多size個位元組,儲存在sink給出的字元陣列中。直至遇到字元delim或者讀滿了size個或遇到檔案尾。delim不讀取,留在輸入流中 |
is.getline(sink, size, delim) | 與上面的get類似,但是會讀取並丟棄delim |
is.read(sink,size) | 讀取最多size個位元組,存入字元陣列sink。返回is |
is.gcount() | 返回上一個未格式化讀取操作從is讀取的位元組數 |
os.write(source, size) | 將字元陣列source中size個位元組寫入os,返回os |
is.ignore(size, delim) | 讀取並忽略最多size個字元,包括delim。size預設為1,delim預設為檔案尾。 |
一般情況下,推薦更安全更高層的操作
- 流隨機訪問
隨機IO本質上依賴於系統
IO型別維護一個標記來確定下一個讀寫操作要在哪裡進行。
istream和ostream通常不支援隨機訪問
操作 | 描述 |
---|---|
tellg() | 返回一個輸入流中標記的當前位置 |
tellp() | 輸出流 |
seekg(pos) | |
seekp(pos) | 輸出流 |
seekg(off, from) | 將一個輸入流中,將標記定位到from前後off個字元的位置 |
seekp(off, from) | from可以是beg,cur,end |
流中只維護單一的標記,對於支援讀寫操作的流,在讀寫之間切換時,必須進行seek操作來重定位標記。
pos和off的型別分別是是pos_type和off_type,是機器相關的,定義在