這篇文章主要介紹“Qt之QRegularExpression正則匹配怎么使用”,在日常操作中,相信很多人在Qt之QRegularExpression正則匹配怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Qt之QRegularExpression正則匹配怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
正則表達式(regep)是處理字符串和文本的強大工具。在許多情況下使用的非常多,就比如在QString 的一些函數API接口參數都是可以傳入 正則表達式的,正則表達式的使用場景有如下幾種,例如:
驗證
regexp可以測試子字符串是否滿足某些條件,例如是整數或不包含空格。
搜索
regexp提供了比簡單子字符串匹配更強大的模式匹配,例如,匹配單詞mail、letter或correspondence中的一個,但不匹配單詞email、mailman、mailer、letterbox等。
搜索和替換
regexp可以用不同的子字符串替換所有出現的子字符串,例如,用&替換所有出現的&;除了&后面已經跟著一個amp;
字符串分割
regexp可用于標識字符串應該在何處分割,例如分割制表符分隔的字符串。
QRegularExpression實現了perl兼容的正則表達式。它完全支持Unicode。有關QRegularExpression支持的正則表達式語法的概述,請參閱前面提到的pcrepattern(3)手冊頁。正則表達式由兩部分組成:一個模式字符串和一組改變模式字符串含義的模式選項。
你可以通過向QRegularExpression構造函數傳遞一個字符串來設置模式字符串:
QRegularExpression re("a pattern");這將模式字符串設置為一個模式。還可以使用setPattern()函數在一個已存在的QRegularExpression對象上設置模式:
QRegularExpression re;
re.setPattern("another pattern");注意,根據c++字符串字面量規則,必須用另一個反斜杠轉義模式字符串中的所有反斜杠:
// matches two digits followed by a space and a word
QRegularExpression re("\\d\\d \\w+");
// matches a backslash
QRegularExpression re2("\\\\");pattern() 函數返回QRegularExpression對象當前設置的模式:
QRegularExpression re("a third pattern");
QString pattern = re.pattern(); // pattern == "a third pattern"可以通過設置一個或多個模式選項來修改模式字符串的含義。例如,可以通過設置QRegularExpression:: caseinsensitive選項來設置模式不區分大小寫。
你可以將這些選項傳遞給QRegularExpression構造函數,如下所示:
// matches "Qt rocks", but also "QT rocks", "QT ROCKS", "qT rOcKs", etc.
QRegularExpression re("Qt rocks", QRegularExpression::CaseInsensitiveOption);或者,你可以在一個已經存在的QRegularExpressionObject上使用setPatternOptions()函數:
QRegularExpression re("^\\d+$");
re.setPatternOptions(QRegularExpression::MultilineOption);
// re matches any line in the subject string that contains only digits (but at least one)使用patternOptions()函數可以獲得QRegularExpression對象當前設置的模式選項:
QRegularExpression re = QRegularExpression("^two.*words$", QRegularExpression::MultilineOption
| QRegularExpression::DotMatchesEverythingOption);
QRegularExpression::PatternOptions options = re.patternOptions();
// options == QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption有關每個模式選項的更多信息,請參閱QRegularExpression::PatternOption enum文檔。
match() 和 globalMatch() 函數的最后兩個參數設置了匹配類型和匹配選項。match類型是QRegularExpression::MatchType enum的值;使用NormalMatch匹配類型(默認值)選擇“傳統”匹配算法。還可以啟用正則表達式對主題字符串的部分匹配:詳細信息請參閱部分匹配部分。
匹配選項是一個或多個QRegularExpression::MatchOption值的集合。它們改變了正則表達式與主題字符串的特定匹配方式。請參閱QRegularExpression::MatchOption枚舉文檔了解更多細節。
要進行匹配,只需調用match()函數,傳入一個要匹配的字符串。我們把這個字符串稱為主題字符串。match()函數的結果是一個QRegularExpressionMatch對象,可用于檢查匹配的結果。例如:
// 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如果匹配成功,(隱式的)捕獲組編號0可以用來檢索整個模式匹配的子字符串(參見提取捕獲子字符串部分):
QRegularExpression re("\\d\\d \\w+");
QRegularExpressionMatch match = re.match("abc123 def");
if (match.hasMatch()) {
QString matched = match.captured(0); // matched == "23 def"
// ...
}也可以將偏移量作為參數傳遞給match()函數,讓匹配從主題字符串中的任意偏移量開始。在下例中,不匹配“12abc”,因為匹配從偏移量1開始:
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"
// ...
}QRegularExpressionMatch對象還包含模式字符串中捕獲組捕獲的子字符串的信息。captured()函數將返回第n個捕獲組捕獲的字符串:
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開始編號,隱式捕獲組0用于捕獲與整個模式匹配的子串。
也可以使用capturedStart()和capturedEnd()函數來取得每個捕獲的子字符串的起始和結束偏移量(在主題字符串中):
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
// ...
}所有這些函數都有一個重載,以QString作為參數,以便提取命名的捕獲子字符串。例如:
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
}全局匹配在查找給定正則表達式在主題字符串中的所有出現情況時非常有用。假設我們想從給定字符串中提取所有的單詞,其中單詞是匹配模式\w+的子字符串。
QRegularExpression::globalMatch返回一個QRegularExpressionMatchIterator對象,這是一個類似java的前向迭代器,可用于迭代結果。例如:
QRegularExpression re("(\\w+)");
QRegularExpressionMatchIterator i = re.globalMatch("the quick fox");由于它是一個類java的迭代器,QRegularExpressionMatchIterator將指向第一個結果的前面。每個結果都以QRegularExpressionMatch對象的形式返回。如果至少有一個結果,hasNext()函數將返回true,而next()將返回下一個結果并推進迭代器。繼續前面的例子:
QStringList words;
while (i.hasNext()) {
QRegularExpressionMatch match = i.next();
QString word = match.captured(1);
words << word;
}
// words contains "the", "quick", "fox"你也可以使用 peekNext() 來獲得下一個結果,而無需推進迭代器。
可以向 globalMatch() 函數傳遞一個起始偏移量和一個或多個匹配選項,就像普通的match()匹配一樣。
當到達主題字符串的結尾時,得到了部分匹配,但要成功完成匹配,需要更多的字符。請注意,部分匹配通常比普通匹配效率低得多,因為無法采用匹配算法的許多優化。
在調用 QRegularExpression::match 或 QRegularExpression::globalMatch 時,必須顯式地指定匹配類型PartialPreferCompleteMatch 或PartialPreferFirstMatch來請求部分匹配。如果找到了部分匹配項,那么在 match() 返回的QRegularExpressionMatch對象上調用hasMatch()函數將返回false,而 hasPartialMatch() 將返回true。
當找到部分匹配時,不返回捕獲子串,整個匹配對應的(隱式)捕獲組0捕獲主題字符串的部分匹配子串。
請注意,請求部分匹配仍然可以得到完全匹配(如果找到的話);在這種情況下,hasMatch()將返回true, hasPartialMatch()返回false。QRegularExpressionMatch從來不會同時報告部分匹配和完全匹配。
部分匹配主要適用于兩種場景:實時驗證用戶輸入和增量/多段匹配。
假設我們希望用戶輸入特定格式的日期,例如“MMM dd, yyyy”。我們可以使用如下模式來檢查輸入的有效性:
^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d?, \d\d\d\d$
(此模式不會捕獲無效日期,但為了示例的目的,我們保留它)。
我們希望在用戶輸入時用這個正則表達式驗證輸入,這樣我們就可以在提交輸入時報告錯誤(例如,用戶輸入了錯誤的鍵)。為此,我們必須區分以下三種情況。
輸入不可能與正則表達式匹配;
輸入確實與正則表達式匹配;
輸入現在還不匹配正則表達式,但如果添加更多字符,它就會匹配。
注意,這三種情況完全代表了QValidator的可能狀態(參見QValidator::State枚舉)。
特別是,在最后一種情況下,我們希望正則表達式引擎報告部分匹配:我們成功地將模式與主題字符串匹配,但匹配不能繼續,因為遇到了主題的結尾。但是請注意,匹配算法應該繼續并嘗試所有的可能性,如果找到了一個完整的(非部分的)匹配,則應該報告這個匹配,并接受輸入字符串,認為它完全有效。
這種行為由PartialPreferCompleteMatch匹配類型實現。例如:
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如果與主題字符串匹配相同的正則表達式得到完全匹配,則像往常一樣報告:
QString input("Dec 8, 1985");
QRegularExpressionMatch match = re.match(input, 0, QRegularExpression::PartialPreferCompleteMatch);
bool hasMatch = match.hasMatch(); // true
bool hasPartialMatch = match.hasPartialMatch(); // false另一個不同模式的例子,展示了完全匹配優于部分匹配的行為:
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"在這個例子中,子模式 abc\w+X 部分匹配主題字符串;然而,子模式def完全匹配主題字符串,因此報告了完全匹配。
如果匹配時發現了多個部分匹配(但沒有完全匹配),那么QRegularExpressionMatch對象將報告第一個找到的匹配。例如:
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"增量匹配是部分匹配的另一種用例。假設我們想找出一個正則表達式在一個大文本中出現的次數(即匹配該正則表達式的子字符串)。為此,我們希望將大型文本以較小的塊“饋送”給正則表達式引擎。一個明顯的問題是,如果與正則表達式匹配的子字符串跨越兩個或多個塊,會發生什么。
在這種情況下,正則表達式引擎應該報告部分匹配,以便我們可以再次匹配,添加新數據,并(最終)得到完全匹配。這意味著正則表達式引擎可能會假設在主題字符串末尾之外還有其他字符。這不是字面上的理解——引擎永遠不會嘗試訪問主題中最后一個字符之后的任何字符。
QRegularExpression 在使用 PartialPreferFirstMatch 匹配類型時實現了這種行為。這種匹配類型一旦找到就報告部分匹配,而不會嘗試其他匹配方案(即使它們可能導致完全匹配)。例如:
QRegularExpression re("abc|ab");
QRegularExpressionMatch match = re.match("ab", 0, QRegularExpression::PartialPreferFirstMatch);
bool hasMatch = match.hasMatch(); // false
bool hasPartialMatch = match.hasPartialMatch(); // true這是因為在匹配交替操作符的第一個分支時,會找到部分匹配,因此匹配會停止,而不會再嘗試第二個分支。另一個例子:
QRegularExpression re("abc(def)?");
QRegularExpressionMatch match = re.match("abc", 0, QRegularExpression::PartialPreferFirstMatch);
bool hasMatch = match.hasMatch(); // false
bool hasPartialMatch = match.hasPartialMatch(); // true這顯示了量詞的一種看似反直覺的行為:since ?是貪婪的,那么引擎在匹配"abc"之后首先嘗試繼續匹配;但隨后匹配到達了主題字符串的末尾,因此報告了部分匹配。在下面的例子中,這更令人驚訝:
QRegularExpression re("(abc)*");
QRegularExpressionMatch match = re.match("abc", 0, QRegularExpression::PartialPreferFirstMatch);
bool hasMatch = match.hasMatch(); // false
bool hasPartialMatch = match.hasPartialMatch(); // true如果我們還記得引擎只希望主題字符串是我們要匹配的整個文本的一個子字符串(也就是說,如前所述,引擎假設主題字符串的結尾之外還有其他字符),那么就很容易理解這種行為了。
由于 * 量詞是貪婪的,那么報告完全匹配可能會出錯,因為在當前主題 “abc” 之后可能還有其他 “abc” 出現。例如,完整文本可以是 “abcabcX” ,因此(在完整文本中)報告的正確匹配應該是 “abcabc” ; 通過只匹配開頭的 “abc” ,我們得到了部分匹配。
QRegularExpression對象可能因為模式字符串中的語法錯誤而無效。如果正則表達式有效,isValid()函數將返回true,否則返回false:
QRegularExpression invalidRe("(unmatched|parenthesis");
bool isValid = invalidRe.isValid(); // false你可以通過調用errorString()函數來獲得有關特定錯誤的更多信息。此外,patternErrorOffset()函數將返回模式字符串中的偏移量
QRegularExpression invalidRe("(unmatched|parenthesis");
if (!invalidRe.isValid()) {
QString errorString = invalidRe.errorString(); // errorString == "missing )"
int errorOffset = invalidRe.patternErrorOffset(); // errorOffset == 22
// ...
}如果試圖匹配無效的QRegularExpressionMatch對象,那么返回的QRegularExpressionMatch對象也將無效(也就是說,它的isValid()函數將返回false)。這同樣適用于嘗試全局匹配。
QRegularExpression不支持perl兼容的正則表達式中的所有特性。最值得注意的是,不支持捕獲組的重復名稱,并且使用它們可能會導致未定義的行為。在Qt的未來版本中,這種情況可能會改變。
Qt 5中引入的QRegularExpression類在提供的api、支持的模式語法和執行速度方面比QRegExp有了很大的改進。最大的區別是QRegularExpression只是保存一個正則表達式,在請求匹配時不會修改它。相反,它會返回一個QRegularExpressionMatch對象,用于檢查匹配的結果并提取捕獲的子字符串。這同樣適用于global matching和QRegularExpressionMatchIterator。其他差異概述如下。
將正則表達式從QRegExp移植到QRegularExpression可能需要修改模式本身。
在某些情況下,QRegExp過于寬松,接受了在使用QRegularExpression時根本無效的模式。這些模式很容易檢測,因為用這些模式構建的QRegularExpression對象是無效的(cf. isValid())。
在其他情況下,從QRegExp移植到QRegularExpression的模式可能會悄無聲息地改變語義。因此,有必要回顧一下所使用的模式。沉默的不兼容最明顯的例子是:
要使用像\xHHHH這樣的十六進制轉義,且轉義的數字超過2位,需要使用大括號。像\x2022這樣的模式需要移植到\x{2022},否則它將匹配一個空格(0x20),后面跟著字符串"22"。一般來說,無論指定多少位數,都強烈建議使用帶\x轉義的大括號。
像{,n}這樣的0到n的量化需要移植到{0,n}以保持語義。否則,像\d{,3}這樣的模式實際上匹配的是一個數字后面跟著一個精確的字符串"{,3}"。
默認情況下,QRegExp執行unicode感知的匹配,而QRegularExpression需要一個單獨的選項。更多細節見下文。
Qt 4中的QRegExp::exactMatch()有兩個用途:一是將正則表達式與主題字符串進行精確匹配,二是實現部分匹配。
從QRegExp的精確匹配進行移植
精確匹配指定正則表達式是否匹配整個主題字符串。例如,這些類會生成主題字符串"abc123":
| QRegExp::exactMatch() | QRegularExpressionMatch::hasMatch() | |
|---|---|---|
| “\d+” | false | true |
| “\d+” | true | true |
精確匹配在QRegularExpression中沒有體現。如果你想確保主題字符串與正則表達式完全匹配,可以使用anchoredPattern()函數來包裝模式:
QString p("a .*|pattern");
// re matches exactly the pattern string p
QRegularExpression re(QRegularExpression::anchoredPattern(p));在使用QRegExp::exactMatch()時,如果沒有找到精確匹配,仍然可以通過調用QRegExp::matchedLength()來找出有多少主題字符串與正則表達式匹配。如果返回的長度等于主題字符串的長度,那么可以斷定找到了部分匹配。
QRegularExpression通過適當的MatchType顯式地支持部分匹配。
由于QRegExp API的限制,無法正確實現全局匹配(也就是說,像Perl那樣)。特別是,可以匹配0個字符的模式(如“a*”)是有問題的。
QRegularExpression::globalMatch()正確地實現了Perl全局匹配,并且返回的迭代器可以用來檢查每個結果。
在使用QRegExp時,字符類如\w、\d等會匹配具有相應Unicode屬性的字符:例如,\d匹配具有Unicode Nd (decimal digit,十進制數字)屬性的任何字符。
在使用QRegularExpression時,這些字符類默認只匹配ASCII字符:例如,\d精確匹配0-9 ASCII范圍內的字符。使用UseUnicodePropertiesOption模式選項可以改變這種行為。
在QRegularExpression中沒有直接的方法來進行通配符匹配。不過,提供了wildcardToRegularExpression方法來將通配模式轉換為perl兼容的正則表達式。
QRegularExpression僅支持perl兼容的正則表達式。
QRegExp::setMinimal()通過簡單地反轉量詞的貪心實現最小匹配(QRegExp不支持惰性量詞,如*?, + ?等)。而QRegularExpression則支持貪心、懶惰和占有量詞。invertedgreedessoption模式選項可以用來模擬QRegExp::setMinimal()的效果:如果啟用,它會反轉量詞的貪婪程度(貪婪的量詞會變成懶惰的量詞,反之亦然)。
插入符號模式
AnchoredMatchOption匹配選項可以用來模擬QRegExp::CaretAtOffset行為。其他的QRegExp::CaretMode模式則沒有對應的選項。
QRegularExpression內部使用JIT (just in time compiler,即時編譯器)來優化匹配算法的執行。JIT大量使用了自修改代碼,這可能會導致Valgrind等調試工具崩潰。如果想使用QRegularExpression(例如,Valgrind的——smc-check命令行選項)調試程序,必須啟用所有自修改代碼的檢查。啟用這種檢查的缺點是程序運行速度會慢得多。
為了避免這種情況,如果你在調試模式下編譯Qt, JIT默認是禁用的。通過將QT_ENABLE_REGEXP_JIT環境變量分別設置為非零或零值,可以覆蓋默認值并啟用或禁用JIT使用(調試模式或釋放模式)。
到此,關于“Qt之QRegularExpression正則匹配怎么使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。