Qt掃盲篇之QRegularExpression正則匹配總結(jié)
一、概述
正則表達(dá)式(regep)是處理字符串和文本的強(qiáng)大工具。在許多情況下使用的非常多,就比如在QString 的一些函數(shù)API接口參數(shù)都是可以傳入 正則表達(dá)式的,正則表達(dá)式的使用場景有如下幾種,例如:
- 驗(yàn)證
regexp可以測試子字符串是否滿足某些條件,例如是整數(shù)或不包含空格。 - 搜索
regexp提供了比簡單子字符串匹配更強(qiáng)大的模式匹配,例如,匹配單詞mail、letter或correspondence中的一個(gè),但不匹配單詞email、mailman、mailer、letterbox等。 - 搜索和替換
regexp可以用不同的子字符串替換所有出現(xiàn)的子字符串,例如,用&替換所有出現(xiàn)的&;除了&后面已經(jīng)跟著一個(gè)amp; - 字符串分割
regexp可用于標(biāo)識(shí)字符串應(yīng)該在何處分割,例如分割制表符分隔的字符串。
本文檔并不是使用正則表達(dá)式進(jìn)行模式匹配的完整參考,以下部分將要求讀者對類perl正則表達(dá)式及其模式語法有一些基本知識(shí)。
基礎(chǔ)的知識(shí)可以看 這里
二、介紹
QRegularExpression實(shí)現(xiàn)了perl兼容的正則表達(dá)式。它完全支持Unicode。有關(guān)QRegularExpression支持的正則表達(dá)式語法的概述,請參閱前面提到的pcrepattern(3)手冊頁。正則表達(dá)式由兩部分組成:一個(gè)模式字符串和一組改變模式字符串含義的模式選項(xiàng)。
你可以通過向QRegularExpression構(gòu)造函數(shù)傳遞一個(gè)字符串來設(shè)置模式字符串:
QRegularExpression re("a pattern");
這將模式字符串設(shè)置為一個(gè)模式。還可以使用setPattern()函數(shù)在一個(gè)已存在的QRegularExpression對象上設(shè)置模式:
QRegularExpression re; re.setPattern("another pattern");
注意,根據(jù)c++字符串字面量規(guī)則,必須用另一個(gè)反斜杠轉(zhuǎn)義模式字符串中的所有反斜杠:
// matches two digits followed by a space and a word QRegularExpression re("\\d\\d \\w+"); // matches a backslash QRegularExpression re2("\\\\");
pattern() 函數(shù)返回QRegularExpression對象當(dāng)前設(shè)置的模式:
QRegularExpression re("a third pattern"); QString pattern = re.pattern(); // pattern == "a third pattern"
三、模式選項(xiàng)
可以通過設(shè)置一個(gè)或多個(gè)模式選項(xiàng)來修改模式字符串的含義。例如,可以通過設(shè)置QRegularExpression:: caseinsensitive選項(xiàng)來設(shè)置模式不區(qū)分大小寫。
你可以將這些選項(xiàng)傳遞給QRegularExpression構(gòu)造函數(shù),如下所示:
// matches "Qt rocks", but also "QT rocks", "QT ROCKS", "qT rOcKs", etc. QRegularExpression re("Qt rocks", QRegularExpression::CaseInsensitiveOption);
或者,你可以在一個(gè)已經(jīng)存在的QRegularExpressionObject上使用setPatternOptions()函數(shù):
QRegularExpression re("^\\d+$"); re.setPatternOptions(QRegularExpression::MultilineOption); // re matches any line in the subject string that contains only digits (but at least one)
使用patternOptions()函數(shù)可以獲得QRegularExpression對象當(dāng)前設(shè)置的模式選項(xiàng):
QRegularExpression re = QRegularExpression("^two.*words$", QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption); QRegularExpression::PatternOptions options = re.patternOptions(); // options == QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption
有關(guān)每個(gè)模式選項(xiàng)的更多信息,請參閱QRegularExpression::PatternOption enum文檔。
四、匹配類型和匹配選項(xiàng)
match() 和 globalMatch() 函數(shù)的最后兩個(gè)參數(shù)設(shè)置了匹配類型和匹配選項(xiàng)。match類型是QRegularExpression::MatchType enum的值;使用NormalMatch匹配類型(默認(rèn)值)選擇“傳統(tǒng)”匹配算法。還可以啟用正則表達(dá)式對主題字符串的部分匹配:詳細(xì)信息請參閱部分匹配部分。
匹配選項(xiàng)是一個(gè)或多個(gè)QRegularExpression::MatchOption值的集合。它們改變了正則表達(dá)式與主題字符串的特定匹配方式。請參閱QRegularExpression::MatchOption枚舉文檔了解更多細(xì)節(jié)。
五、正常的匹配
要進(jìn)行匹配,只需調(diào)用match()函數(shù),傳入一個(gè)要匹配的字符串。我們把這個(gè)字符串稱為主題字符串。match()函數(shù)的結(jié)果是一個(gè)QRegularExpressionMatch對象,可用于檢查匹配的結(jié)果。例如:
// match two digits followed by a space and a word QRegularExpression re("\\d\\d \\w+"); QRegularExpressionMatch match = re.match("abc123 def"); bool hasMatch = match.hasMatch(); // true
如果匹配成功,(隱式的)捕獲組編號(hào)0可以用來檢索整個(gè)模式匹配的子字符串(參見提取捕獲子字符串部分):
QRegularExpression re("\\d\\d \\w+"); QRegularExpressionMatch match = re.match("abc123 def"); if (match.hasMatch()) { QString matched = match.captured(0); // matched == "23 def" // ... }
也可以將偏移量作為參數(shù)傳遞給match()函數(shù),讓匹配從主題字符串中的任意偏移量開始。在下例中,不匹配“12abc”,因?yàn)槠ヅ鋸钠屏?開始:
QRegularExpression re("\\d\\d \\w+"); QRegularExpressionMatch match = re.match("12 abc 45 def", 1); if (match.hasMatch()) { QString matched = match.captured(0); // matched == "45 def" // ... }
1. 提取捕獲的子字符串
QRegularExpressionMatch對象還包含模式字符串中捕獲組捕獲的子字符串的信息。captured()函數(shù)將返回第n個(gè)捕獲組捕獲的字符串:
QRegularExpression re("^(\\d\\d)/(\\d\\d)/(\\d\\d\\d\\d)$"); QRegularExpressionMatch match = re.match("08/12/1985"); if (match.hasMatch()) { QString day = match.captured(1); // day == "08" QString month = match.captured(2); // month == "12" QString year = match.captured(3); // year == "1985" // ... }
模式中的捕獲組從1開始編號(hào),隱式捕獲組0用于捕獲與整個(gè)模式匹配的子串。
也可以使用capturedStart()和capturedEnd()函數(shù)來取得每個(gè)捕獲的子字符串的起始和結(jié)束偏移量(在主題字符串中):
QRegularExpression re("abc(\\d+)def"); QRegularExpressionMatch match = re.match("XYZabc123defXYZ"); if (match.hasMatch()) { int startOffset = match.capturedStart(1); // startOffset == 6 int endOffset = match.capturedEnd(1); // endOffset == 9 // ... }
所有這些函數(shù)都有一個(gè)重載,以QString作為參數(shù),以便提取命名的捕獲子字符串。例如:
QRegularExpression re("^(?<date>\\d\\d)/(?<month>\\d\\d)/(?<year>\\d\\d\\d\\d)$"); QRegularExpressionMatch match = re.match("08/12/1985"); if (match.hasMatch()) { QString date = match.captured("date"); // date == "08" QString month = match.captured("month"); // month == "12" QString year = match.captured("year"); // year == 1985 }
六、全局匹配
全局匹配在查找給定正則表達(dá)式在主題字符串中的所有出現(xiàn)情況時(shí)非常有用。假設(shè)我們想從給定字符串中提取所有的單詞,其中單詞是匹配模式\w+的子字符串。
QRegularExpression::globalMatch返回一個(gè)QRegularExpressionMatchIterator對象,這是一個(gè)類似java的前向迭代器,可用于迭代結(jié)果。例如:
QRegularExpression re("(\\w+)"); QRegularExpressionMatchIterator i = re.globalMatch("the quick fox");
由于它是一個(gè)類java的迭代器,QRegularExpressionMatchIterator將指向第一個(gè)結(jié)果的前面。每個(gè)結(jié)果都以QRegularExpressionMatch對象的形式返回。如果至少有一個(gè)結(jié)果,hasNext()函數(shù)將返回true,而next()將返回下一個(gè)結(jié)果并推進(jìn)迭代器。繼續(xù)前面的例子:
QStringList words; while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString word = match.captured(1); words << word; } // words contains "the", "quick", "fox"
你也可以使用 peekNext() 來獲得下一個(gè)結(jié)果,而無需推進(jìn)迭代器。
可以向 globalMatch() 函數(shù)傳遞一個(gè)起始偏移量和一個(gè)或多個(gè)匹配選項(xiàng),就像普通的match()匹配一樣。
七、部分匹配
當(dāng)?shù)竭_(dá)主題字符串的結(jié)尾時(shí),得到了部分匹配,但要成功完成匹配,需要更多的字符。請注意,部分匹配通常比普通匹配效率低得多,因?yàn)闊o法采用匹配算法的許多優(yōu)化。
在調(diào)用 QRegularExpression::match 或 QRegularExpression::globalMatch 時(shí),必須顯式地指定匹配類型PartialPreferCompleteMatch 或PartialPreferFirstMatch來請求部分匹配。如果找到了部分匹配項(xiàng),那么在 match() 返回的QRegularExpressionMatch對象上調(diào)用hasMatch()函數(shù)將返回false,而 hasPartialMatch() 將返回true。
當(dāng)找到部分匹配時(shí),不返回捕獲子串,整個(gè)匹配對應(yīng)的(隱式)捕獲組0捕獲主題字符串的部分匹配子串。
請注意,請求部分匹配仍然可以得到完全匹配(如果找到的話);在這種情況下,hasMatch()將返回true, hasPartialMatch()返回false。QRegularExpressionMatch從來不會(huì)同時(shí)報(bào)告部分匹配和完全匹配。
部分匹配主要適用于兩種場景:實(shí)時(shí)驗(yàn)證用戶輸入和增量/多段匹配。
1. 驗(yàn)證用戶輸入
假設(shè)我們希望用戶輸入特定格式的日期,例如“MMM dd, yyyy”。我們可以使用如下模式來檢查輸入的有效性:
- ^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d?, \d\d\d\d$
(此模式不會(huì)捕獲無效日期,但為了示例的目的,我們保留它)。
我們希望在用戶輸入時(shí)用這個(gè)正則表達(dá)式驗(yàn)證輸入,這樣我們就可以在提交輸入時(shí)報(bào)告錯(cuò)誤(例如,用戶輸入了錯(cuò)誤的鍵)。為此,我們必須區(qū)分以下三種情況。
- 輸入不可能與正則表達(dá)式匹配;
- 輸入確實(shí)與正則表達(dá)式匹配;
- 輸入現(xiàn)在還不匹配正則表達(dá)式,但如果添加更多字符,它就會(huì)匹配。
注意,這三種情況完全代表了QValidator的可能狀態(tài)(參見QValidator::State枚舉)。
特別是,在最后一種情況下,我們希望正則表達(dá)式引擎報(bào)告部分匹配:我們成功地將模式與主題字符串匹配,但匹配不能繼續(xù),因?yàn)橛龅搅酥黝}的結(jié)尾。但是請注意,匹配算法應(yīng)該繼續(xù)并嘗試所有的可能性,如果找到了一個(gè)完整的(非部分的)匹配,則應(yīng)該報(bào)告這個(gè)匹配,并接受輸入字符串,認(rèn)為它完全有效。
這種行為由PartialPreferCompleteMatch匹配類型實(shí)現(xiàn)。例如:
QString pattern("^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \\d\\d?, \\d\\d\\d\\d$"); QRegularExpression re(pattern); QString input("Jan 21,"); QRegularExpressionMatch match = re.match(input, 0, QRegularExpression::PartialPreferCompleteMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true
如果與主題字符串匹配相同的正則表達(dá)式得到完全匹配,則像往常一樣報(bào)告:
QString input("Dec 8, 1985"); QRegularExpressionMatch match = re.match(input, 0, QRegularExpression::PartialPreferCompleteMatch); bool hasMatch = match.hasMatch(); // true bool hasPartialMatch = match.hasPartialMatch(); // false
另一個(gè)不同模式的例子,展示了完全匹配優(yōu)于部分匹配的行為:
QRegularExpression re("abc\\w+X|def"); QRegularExpressionMatch match = re.match("abcdef", 0, QRegularExpression::PartialPreferCompleteMatch); bool hasMatch = match.hasMatch(); // true bool hasPartialMatch = match.hasPartialMatch(); // false QString captured = match.captured(0); // captured == "def"
在這個(gè)例子中,子模式 abc\w+X 部分匹配主題字符串;然而,子模式def完全匹配主題字符串,因此報(bào)告了完全匹配。
如果匹配時(shí)發(fā)現(xiàn)了多個(gè)部分匹配(但沒有完全匹配),那么QRegularExpressionMatch對象將報(bào)告第一個(gè)找到的匹配。例如:
QRegularExpression re("abc\\w+X|defY"); QRegularExpressionMatch match = re.match("abcdef", 0, QRegularExpression::PartialPreferCompleteMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true QString captured = match.captured(0); // captured == "abcdef"
2. 增量/為多段匹配
增量匹配是部分匹配的另一種用例。假設(shè)我們想找出一個(gè)正則表達(dá)式在一個(gè)大文本中出現(xiàn)的次數(shù)(即匹配該正則表達(dá)式的子字符串)。為此,我們希望將大型文本以較小的塊“饋送”給正則表達(dá)式引擎。一個(gè)明顯的問題是,如果與正則表達(dá)式匹配的子字符串跨越兩個(gè)或多個(gè)塊,會(huì)發(fā)生什么。
在這種情況下,正則表達(dá)式引擎應(yīng)該報(bào)告部分匹配,以便我們可以再次匹配,添加新數(shù)據(jù),并(最終)得到完全匹配。這意味著正則表達(dá)式引擎可能會(huì)假設(shè)在主題字符串末尾之外還有其他字符。這不是字面上的理解——引擎永遠(yuǎn)不會(huì)嘗試訪問主題中最后一個(gè)字符之后的任何字符。
QRegularExpression 在使用 PartialPreferFirstMatch 匹配類型時(shí)實(shí)現(xiàn)了這種行為。這種匹配類型一旦找到就報(bào)告部分匹配,而不會(huì)嘗試其他匹配方案(即使它們可能導(dǎo)致完全匹配)。例如:
QRegularExpression re("abc|ab"); QRegularExpressionMatch match = re.match("ab", 0, QRegularExpression::PartialPreferFirstMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true
這是因?yàn)樵谄ヅ浣惶娌僮鞣牡谝粋€(gè)分支時(shí),會(huì)找到部分匹配,因此匹配會(huì)停止,而不會(huì)再嘗試第二個(gè)分支。另一個(gè)例子:
QRegularExpression re("abc(def)?"); QRegularExpressionMatch match = re.match("abc", 0, QRegularExpression::PartialPreferFirstMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true
這顯示了量詞的一種看似反直覺的行為:since ?是貪婪的,那么引擎在匹配"abc"之后首先嘗試?yán)^續(xù)匹配;但隨后匹配到達(dá)了主題字符串的末尾,因此報(bào)告了部分匹配。在下面的例子中,這更令人驚訝:
QRegularExpression re("(abc)*"); QRegularExpressionMatch match = re.match("abc", 0, QRegularExpression::PartialPreferFirstMatch); bool hasMatch = match.hasMatch(); // false bool hasPartialMatch = match.hasPartialMatch(); // true
如果我們還記得引擎只希望主題字符串是我們要匹配的整個(gè)文本的一個(gè)子字符串(也就是說,如前所述,引擎假設(shè)主題字符串的結(jié)尾之外還有其他字符),那么就很容易理解這種行為了。
由于 * 量詞是貪婪的,那么報(bào)告完全匹配可能會(huì)出錯(cuò),因?yàn)樵诋?dāng)前主題 “abc” 之后可能還有其他 “abc” 出現(xiàn)。例如,完整文本可以是 “abcabcX” ,因此(在完整文本中)報(bào)告的正確匹配應(yīng)該是 “abcabc” ; 通過只匹配開頭的 “abc” ,我們得到了部分匹配。
八、錯(cuò)誤處理
QRegularExpression對象可能因?yàn)槟J阶址械恼Z法錯(cuò)誤而無效。如果正則表達(dá)式有效,isValid()函數(shù)將返回true,否則返回false:
QRegularExpression invalidRe("(unmatched|parenthesis"); bool isValid = invalidRe.isValid(); // false
你可以通過調(diào)用errorString()函數(shù)來獲得有關(guān)特定錯(cuò)誤的更多信息。此外,patternErrorOffset()函數(shù)將返回模式字符串中的偏移量
QRegularExpression invalidRe("(unmatched|parenthesis"); if (!invalidRe.isValid()) { QString errorString = invalidRe.errorString(); // errorString == "missing )" int errorOffset = invalidRe.patternErrorOffset(); // errorOffset == 22 // ... }
如果試圖匹配無效的QRegularExpressionMatch對象,那么返回的QRegularExpressionMatch對象也將無效(也就是說,它的isValid()函數(shù)將返回false)。這同樣適用于嘗試全局匹配。
九、不支持perl兼容的正則表達(dá)式特性
QRegularExpression不支持perl兼容的正則表達(dá)式中的所有特性。最值得注意的是,不支持捕獲組的重復(fù)名稱,并且使用它們可能會(huì)導(dǎo)致未定義的行為。在Qt的未來版本中,這種情況可能會(huì)改變。
十、QRegExp用戶的注意事項(xiàng)
Qt 5中引入的QRegularExpression類在提供的api、支持的模式語法和執(zhí)行速度方面比QRegExp有了很大的改進(jìn)。最大的區(qū)別是QRegularExpression只是保存一個(gè)正則表達(dá)式,在請求匹配時(shí)不會(huì)修改它。相反,它會(huì)返回一個(gè)QRegularExpressionMatch對象,用于檢查匹配的結(jié)果并提取捕獲的子字符串。這同樣適用于global matching和QRegularExpressionMatchIterator。其他差異概述如下。
1. 不同的模式語法
將正則表達(dá)式從QRegExp移植到QRegularExpression可能需要修改模式本身。
在某些情況下,QRegExp過于寬松,接受了在使用QRegularExpression時(shí)根本無效的模式。這些模式很容易檢測,因?yàn)橛眠@些模式構(gòu)建的QRegularExpression對象是無效的(cf. isValid())。
在其他情況下,從QRegExp移植到QRegularExpression的模式可能會(huì)悄無聲息地改變語義。因此,有必要回顧一下所使用的模式。沉默的不兼容最明顯的例子是:
要使用像\xHHHH這樣的十六進(jìn)制轉(zhuǎn)義,且轉(zhuǎn)義的數(shù)字超過2位,需要使用大括號(hào)。像\x2022這樣的模式需要移植到\x{2022},否則它將匹配一個(gè)空格(0x20),后面跟著字符串"22"。一般來說,無論指定多少位數(shù),都強(qiáng)烈建議使用帶\x轉(zhuǎn)義的大括號(hào)。
像{,n}這樣的0到n的量化需要移植到{0,n}以保持語義。否則,像\d{,3}這樣的模式實(shí)際上匹配的是一個(gè)數(shù)字后面跟著一個(gè)精確的字符串"{,3}"。
默認(rèn)情況下,QRegExp執(zhí)行unicode感知的匹配,而QRegularExpression需要一個(gè)單獨(dú)的選項(xiàng)。更多細(xì)節(jié)見下文。
2. 從QRegExp::exactMatch()移植
Qt 4中的QRegExp::exactMatch()有兩個(gè)用途:一是將正則表達(dá)式與主題字符串進(jìn)行精確匹配,二是實(shí)現(xiàn)部分匹配。
從QRegExp的精確匹配進(jìn)行移植
精確匹配指定正則表達(dá)式是否匹配整個(gè)主題字符串。例如,這些類會(huì)生成主題字符串"abc123":
QRegExp::exactMatch() | QRegularExpressionMatch::hasMatch() | |
---|---|---|
“\d+” | false | true |
“\d+” | true | true |
精確匹配在QRegularExpression中沒有體現(xiàn)。如果你想確保主題字符串與正則表達(dá)式完全匹配,可以使用anchoredPattern()函數(shù)來包裝模式:
QString p("a .*|pattern"); // re matches exactly the pattern string p QRegularExpression re(QRegularExpression::anchoredPattern(p));
在使用QRegExp::exactMatch()時(shí),如果沒有找到精確匹配,仍然可以通過調(diào)用QRegExp::matchedLength()來找出有多少主題字符串與正則表達(dá)式匹配。如果返回的長度等于主題字符串的長度,那么可以斷定找到了部分匹配。
QRegularExpression通過適當(dāng)?shù)腗atchType顯式地支持部分匹配。
3. Global匹配
由于QRegExp API的限制,無法正確實(shí)現(xiàn)全局匹配(也就是說,像Perl那樣)。特別是,可以匹配0個(gè)字符的模式(如“a*”)是有問題的。
QRegularExpression::globalMatch()正確地實(shí)現(xiàn)了Perl全局匹配,并且返回的迭代器可以用來檢查每個(gè)結(jié)果。
4. 支持Unicode屬性
在使用QRegExp時(shí),字符類如\w、\d等會(huì)匹配具有相應(yīng)Unicode屬性的字符:例如,\d匹配具有Unicode Nd (decimal digit,十進(jìn)制數(shù)字)屬性的任何字符。
在使用QRegularExpression時(shí),這些字符類默認(rèn)只匹配ASCII字符:例如,\d精確匹配0-9 ASCII范圍內(nèi)的字符。使用UseUnicodePropertiesOption模式選項(xiàng)可以改變這種行為。
5. 通配符匹配
在QRegularExpression中沒有直接的方法來進(jìn)行通配符匹配。不過,提供了wildcardToRegularExpression方法來將通配模式轉(zhuǎn)換為perl兼容的正則表達(dá)式。
6. 其他模式語法
QRegularExpression僅支持perl兼容的正則表達(dá)式。
7. 最小的匹配
QRegExp::setMinimal()通過簡單地反轉(zhuǎn)量詞的貪心實(shí)現(xiàn)最小匹配(QRegExp不支持惰性量詞,如*?, + ?等)。而QRegularExpression則支持貪心、懶惰和占有量詞。invertedgreedessoption模式選項(xiàng)可以用來模擬QRegExp::setMinimal()的效果:如果啟用,它會(huì)反轉(zhuǎn)量詞的貪婪程度(貪婪的量詞會(huì)變成懶惰的量詞,反之亦然)。
插入符號(hào)模式
AnchoredMatchOption匹配選項(xiàng)可以用來模擬QRegExp::CaretAtOffset行為。其他的QRegExp::CaretMode模式則沒有對應(yīng)的選項(xiàng)。
十一、調(diào)試使用QRegularExpression的代碼
QRegularExpression內(nèi)部使用JIT (just in time compiler,即時(shí)編譯器)來優(yōu)化匹配算法的執(zhí)行。JIT大量使用了自修改代碼,這可能會(huì)導(dǎo)致Valgrind等調(diào)試工具崩潰。如果想使用QRegularExpression(例如,Valgrind的——smc-check命令行選項(xiàng))調(diào)試程序,必須啟用所有自修改代碼的檢查。啟用這種檢查的缺點(diǎn)是程序運(yùn)行速度會(huì)慢得多。
為了避免這種情況,如果你在調(diào)試模式下編譯Qt, JIT默認(rèn)是禁用的。通過將QT_ENABLE_REGEXP_JIT環(huán)境變量分別設(shè)置為非零或零值,可以覆蓋默認(rèn)值并啟用或禁用JIT使用(調(diào)試模式或釋放模式)。
總結(jié)
到此這篇關(guān)于Qt掃盲篇之QRegularExpression正則匹配總結(jié)的文章就介紹到這了,更多相關(guān)Qt QRegularExpression正則匹配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vc中float與DWORD的互想轉(zhuǎn)換實(shí)現(xiàn)代碼
這篇文章主要介紹了vc中float與DWORD的互想轉(zhuǎn)換實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-06-06解決VC++編譯報(bào)錯(cuò)error C2248的方案
這篇文章主要介紹了解決VC++編譯報(bào)錯(cuò)error C2248的方案的相關(guān)資料,需要的朋友可以參考下2015-11-11Qt使用QPainter實(shí)現(xiàn)自定義圓形進(jìn)度條
這篇文章主要介紹了Qt如何使用QPainter實(shí)現(xiàn)自定義圓形進(jìn)度條功能,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Qt有一定的幫助,需要的可以參考一下2022-06-06