QVariant

QVariant類別類似c++的聯合(union)數據類型,能夠保存許多Qt類別的值,包括int、QString、QColor、QPen、QRect、QSize等,也能夠存Qt的容器。

這邊用QVariant保留各類型的值,要使用時再轉型成原本儲存的類型。


#include <QCoreApplication>
#include<QDebug>
#include <QVariant>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QVariant int_v(20);
    qDebug()<<int_v.toInt();

    QVariant double_v(20.5);
    qDebug()<<double_v.toDouble();

    QVariant string_v("Hi");
    qDebug()<<string_v.toString();

    QStringList sl;
    sl<<"a"<<"b";
    QVariant sl_v(sl);
    if(sl_v.type()==QVariant::StringList){      //判斷QVariant的類型是否為StringList
        QStringList list=sl_v.toStringList();
        for(int i=0;i<list.size();++i)
            qDebug()<<list.at(i);
    }
    return 0;
} 

QVariant

隱式共享(copy on write)

隱式共享又稱之為copy on write,意旨當兩個對象共享一份數據時,如果數據不改變,就不進行數據的複製,而當某個對象需要改變數據時,才對資料進行複製。隱式共享可以降低內存和CPU資源的使用效率,像函數的參數或返回值使用值傳遞更有效率。

共享包含了數據本身以及數據的引用計數,當對象創建出來時,引用計數被設置為1,當有新的對象引用到共享數據時,引用計數增加,當有對象不再引用數據時,引用計數減少,當引用計數變為0 時,共享數據被刪除。

在我們操作共享數據時,有深拷貝和淺拷貝兩種拷貝方式,深拷貝會重新複製一個對象;淺拷貝則僅複製指向共享數據塊的指針,因為淺拷貝僅設置一個新的指針,然後將引用計數加1,所以對資源的消耗較少。

  QString str1 = “hello”;  
  QString str2 = str1;    //str2="hello"
  str2[0] = 'a';          //str2="aello" str1="hello"
  str2[0] = 'b';          //str2="bello" str1="hello"
  • QString str2 = str1:在對str2賦值時進行淺拷貝,兩個QString對象都指向同一個數據結構,此結構除了保持字串”hello”外,還保有一個計數器,因為str1和str2皆指向這個數據結構,因此計數器值為2。
  • str2[0] = ‘a’:str2的更改會導致一個深拷貝,使得str2指向一個新的結構,str1和str2指向的結構計數器皆為1。
  • str2[0] = ‘b’:str2的更改不會引起任何的複製,因為str2指向的結構沒有被共享。
  • str1 = str2:str1原本指像的結構計數器變為0,因此指結構會從內存中被釋放掉,str1和str2接指向相同的結構,此結構計數器為2。

Qt許多類別使用了隱式共享技術,且隱式共享是在底層自動完成的,我們不必另外撰寫程式碼,對於QList或者QVector,應該使用at()函數而不是[]操作符進行只讀訪問,原因是Qt容器無法判斷[]操作符是左值還是右值,進而無法隱式數據共享,對於begin(),end()等遍歷器,由於數據可能改變,因此Qt會進行深拷貝,所以當我們容器內物件值不會變動時,盡可能使用const_iterator、constBegin()和constEnd(),這樣會有較佳的效率。

正規表達式(Regular Expression)

正規表達式(Regular Expression,程式碼常簡寫為regex),使用單個字串來描述、匹配符合規則的字串,通常被用來檢索、取代符合某個模式的文字,主要由表達式、量詞、斷言三部分組成。


表達式是各種字符或字符集:

  • 最簡單的表達式為一個字符,像a或0。
  • 如果是一組字符可使用方括號,像[abc]會匹配一個a或b或c,和[a-c]兩者意思相等。
  • ^表示相反意思,像[^abc]表示匹配任何字符,除了a或b或c。

以下列較常用的字符或字符集:

元素 含意
c字符本身,例如a匹配a
\d匹配一個數字
\D匹配一個非數字
\s匹配一個空白字符,像’\t’、’\n’、’\v’、 ’\f’、’ ’
\S匹配一個非空白字符
\w匹配一個任意字母、數字、下畫線,像a-z、A-Z、0-9、_,任意一個
\W匹配任意一個非單詞字符


量詞表示匹配的表達式出現次數:

  • 默認為{1,1},表示匹配剛好一個。
  • a{1,2}表示匹配字符a,至少要一個,最多兩個。

以下列出常用的量詞:

量詞含意
E?匹配0次或1次,等同於E{0,1}
E+匹配1次或多次,等同於E{1,}
E*匹配0次或多次,等同於E{0,}
E{n}匹配n次,等同於E{n,n}
E{n,}匹配至少n次
E{,m}匹配至多m次,等同於E{0,m}
E{n,m}匹配至少n次,至多m次


斷言表示匹配的前後位置,以下列出常用的斷言:

斷言 含意
^表示字串的開始
$表示字串的結束
\b表示匹配一個位置,也就是一個空格或新行
\B表示匹配一個字符,和\b相反
(?=E)表達式後緊跟著E才匹配
(?! E)表達式後沒有緊跟著E才匹配


假設我們想要匹配0~99之間的整數,可以寫成[0-9]{1,2},如果想匹配的是整個字符串,就須加上^和$,所以想匹配0~99的表達式為^[0-9]{1,2}$,可用\d來代替[0-9],用?代替{0,1},所以也可以寫成^\d{1,2}$或^\d\d{0,1}$或^\d\d?$。


假如我們想匹配"key"或"test",但不是某些字串的子自串,像"turkey",表達式裡 | 表示或的意思,\b斷言表示單詞的邊界是個非單詞字符,如一個空格或新行,所以想匹配"key"或"test"的表達式為\b(key|test)\b。


C++中"\d"是轉義字符,所以表達式裡要用時,要將"\d"寫成"\d"。