QRegExp Class

QRegExp 类使用正则表达式进行模式匹配。更多

Header: #include <QRegExp>
CMake: find_package(Qt6 REQUIRED COMPONENTS Core5Compat)
target_link_libraries(mytarget PRIVATE Qt6::Core5Compat)
qmake: QT += core5compat

注意:该类中的所有函数都是可重入的

公共类型

enum CaretMode { CaretAtZero, CaretAtOffset, CaretWontMatch }
enum PatternSyntax { RegExp, RegExp2, Wildcard, WildcardUnix, FixedString, W3CXmlSchema11 }

公共函数

QRegExp()
QRegExp(const QString &pattern, Qt::CaseSensitivity cs = Qt::CaseSensitive, QRegExp::PatternSyntax syntax = RegExp)
QRegExp(const QRegExp &rx)
~QRegExp()
QString cap(int nth = 0) const
int captureCount() const
QStringList capturedTexts() const
Qt::CaseSensitivity caseSensitivity() const
int countIn(const QString &str) const
QString errorString() const
bool exactMatch(const QString &str) const
QStringList filterList(const QStringList &stringList) const
int indexIn(const QStringList &list, int from) const
int indexIn(const QString &str, int offset = 0, QRegExp::CaretMode caretMode = CaretAtZero) const
bool isEmpty() const
bool isMinimal() const
bool isValid() const
int lastIndexIn(const QStringList &list, int from) const
int lastIndexIn(const QString &str, int offset = -1, QRegExp::CaretMode caretMode = CaretAtZero) const
int matchedLength() const
QString pattern() const
QRegExp::PatternSyntax patternSyntax() const
int pos(int nth = 0) const
QString removeIn(const QString &str) const
QString replaceIn(const QString &str, const QString &after) const
QStringList replaceIn(const QStringList &stringList, const QString &after) const
void setCaseSensitivity(Qt::CaseSensitivity cs)
void setMinimal(bool minimal)
void setPattern(const QString &pattern)
void setPatternSyntax(QRegExp::PatternSyntax syntax)
QStringList splitString(const QString &str, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const
void swap(QRegExp &other)
QVariant operator QVariant() const
bool operator!=(const QRegExp &rx) const
QRegExp &operator=(QRegExp &&other)
QRegExp &operator=(const QRegExp &rx)
bool operator==(const QRegExp &rx) const

静态公共成员

QString escape(const QString &str)
size_t qHash(const QRegExp &key, size_t seed = 0)
QDataStream &operator<<(QDataStream &out, const QRegExp &regExp)
QDataStream &operator>>(QDataStream &in, QRegExp &regExp)

详细说明

该类在 Qt 6 中已被弃用。所有新代码请使用QRegularExpression 代替。有关将旧代码从 QRegExp 移植到QRegularExpression 的指南,请参阅 {Porting toQRegularExpression}。

正则表达式或 "regexp "是一种用于匹配文本中子串的模式。这在很多情况下都很有用,例如

验证正则表达式可以测试子串是否符合某些条件,例如是否是整数或是否不包含空白。
搜索与简单的子字符串匹配相比,regexp 提供了更强大的模式匹配功能,例如,匹配maillettercorrespondence 中的一个单词,但不匹配emailmailman、 mailerletterbox 等单词。
搜索和替换regexp 可以用不同的子串替换所有出现的子串,例如,用&amp;替换所有出现的&,除非&后面已经有amp;
字符串分割regexp 可用于识别字符串应分割的位置,例如分割以制表符分隔的字符串。

本文将简要介绍 regexp、Qt regexp 语言的说明、一些示例以及函数文档本身。QRegExp 以 Perl 的 regexp 语言为模型。它完全支持 Unicode。QRegExp 还可以在更简单的通配符模式下使用,这种模式与命令 shell 中的功能类似。QRegExp 使用的语法规则可以通过setPatternSyntax() 进行更改。特别是,可以将模式语法设置为QRegExp::FixedString ,这意味着要匹配的模式被解释为纯字符串,即特殊字符(如反斜杠)不会被转义。

关于 regexps 的一本好书是 Jeffrey E. F. Friedl 所著的《精通正则表达式(第三版)》(Mastering Regular Expressions(Third Edition)),ISBN 0-596-52812-4。

注: 在 Qt 5 中,新的QRegularExpression 类提供了与 Perl 兼容的正则表达式实现,建议用它代替 QRegExp。

简介

正则表达式由表达式、量词和断言组成。最简单的表达式是一个字符,例如x5。表达式也可以是用方括号括起来的一组字符。[ABCD]将匹配一个A或一个B或一个C或一个D。我们可以把这个表达式写成[A-D],而匹配英文字母表中任何大写字母的表达式则写成[A - Z]

x{1,1}表示匹配一个且仅匹配一个xx { 1, 5 }表示匹配至少包含一个x 但不超过五个xx字符序列。

请注意,一般情况下,regexp 不能用于检查平衡括号或标记。例如,如果<b> 标记没有嵌套,可以编写一个 regexp 来匹配开头的 html<b> 及其结尾的</b> ,但如果<b> 标记有嵌套,同样的 regexp 将匹配开头的<b> 标记和错误的结尾</b> 。对于片段<b>bold <b>bolder</b></b> ,第一个<b> 将与第一个</b> 匹配,这是不正确的。不过,也可以编写能正确匹配嵌套括号或标记的 regexp,但前提是嵌套层的数量是固定且已知的。如果嵌套层数不固定且已知,就不可能编写出不会失败的 regexp。

假设我们需要一个 regexp 来匹配范围在 0 到 99 之间的整数,至少需要一位数字,因此我们从表达式[0-9]{1,1} 开始,它只匹配一位数字一次。这个 regexp 可以匹配 0 到 9 范围内的整数。要匹配 99 位以内的整数,可将最大出现次数增加到 2,这样 regexp 就变成了[0-9]{1,2}。这个 regexp 满足了最初的要求,即匹配 0 到 99 之间的整数,但它也会匹配字符串中间出现的整数。如果我们希望匹配的整数是整个字符串,就必须使用锚断言,即^(圆头)和$(美元)。当^是 regexp 中的第一个字符时,表示 regexp 必须从字符串的开头开始匹配。当$是 regexp 的最后一个字符时,表示 regexp 必须匹配到字符串的末尾。regexp 就变成了 ^[0-9]{1,2}$。请注意,断言(如^$)并不匹配字符,而是匹配字符串中的位置。

如果你在其他地方看到过 regexp 的描述,它们可能与这里显示的不同。这是因为某些字符集和某些量词非常常见,所以用特殊符号来表示。[0-9]可以用符号\d 代替。因此,我们的 0 到 99 匹配器可以写成^\d{1 , 2}$ 。也可以写成 ^\d\d{0,1}$ ,即从字符串的开头开始匹配一个数字,紧接着匹配 0 或 1 个数字。实际上,它可以写成 ^\d\d?$?是量词{0,1}的缩写,即 0 或 1 次出现。表示表达式是可选的regexp ^\d\d?$表示从字符串的开头开始,匹配一个数字,紧接着匹配 0 或 1 个数字,紧接着匹配字符串的结尾

如果要编写一个 regexp,匹配 "邮件""信件 ""信函 "中的一个词,但不匹配包含这些词的词,例如 "电子邮件"、"邮递员"、"邮递员 "和 "信箱",则以匹配 "邮件 "的 regexp 开始。完全表达时,regexp 是m{1,1}a{1,1}i{1,1}l{1,1},但由于字符表达式会自动用{1,1} 量化,因此我们可以将 regexp 简化为mail,即一个 "m "后接一个 "a",一个 "i "后接一个 "l"。现在,我们可以使用表示or 的竖条| 来包含另外两个单词,因此匹配这三个单词中任何一个的 regexp 就变成了mail|letter|correspondence。匹配 "mail""letter ""respondence"。虽然这个 regexp 可以匹配我们想要匹配的三个单词中的一个,但它也会匹配我们不想匹配的单词,例如 "email"。为了防止 regexp 匹配到不想要的单词,我们必须告诉它在单词边界开始和结束匹配。首先,我们用括号(mail|letter|correspondence)括起 regexp。括号将表达式组合在一起,它们标识了我们希望capture 的 regexp 的一部分。用括号括起来的表达式允许我们将其用作更复杂 regexp 的一个组成部分。同时,我们还可以检查这三个单词中哪个单词实际被匹配。为了强制匹配以单词边界开始和结束,我们用\b 单词边界断言来括弧 regexp:\b(mail|letter|correspondence)\b。现在 regexp 的意思是匹配单词边界,然后是括号中的 regexp,最后是单词边界\b断言匹配的是 regexp 中的一个位置,而不是一个字符。单词边界是指任何非单词字符,例如空格、换行符、字符串的开头或结尾。

如果我们想用 HTML 实体&amp; 替换安培字符,那么要匹配的 regexp 就是&。但这个 regexp 也会匹配已经转换为 HTML 实体的逗号。我们只想替换那些后面还没有跟上amp; 的标点符号。为此,我们需要使用负前瞻断言(?!__) 。这样,regexp 就可以写成&(?!amp;),即匹配 后面 没有 amp;逗号

如果我们要计算一个字符串中所有出现的 "Eric "和 "Eirik",有两个有效的解决方案:\b(Eric|Eirik)\b 和 \bEi?ri[ck]\b。词边界断言"\b "是必需的,以避免匹配包含两个名字的词,例如 "Ericsson"。请注意,第二个 regexp 匹配的拼写比我们想要的多:"Eric"、"Erik"、"Eiric "和 "Eirik"。

上面讨论的一些例子将在code examples 部分实现。

字符和字符集缩写

元素含义
c除非具有特殊的 regexp 意义,否则一个字符代表它自己。例如,c与字符c 匹配。
\c反斜杠后的字符与字符本身匹配,但下文中指定的情况除外。例如,要匹配字符串开头的字面空格,写 \^
\a匹配 ASCII 钟形字符(BEL, 0x07)。
\f匹配 ASCII 换页符(FF, 0x0C)。
\n匹配 ASCII 换行符(LF, 0x0A, Unix 换行符)。
\r匹配 ASCII 字符回车(CR, 0x0D)。
\t匹配 ASCII 水平制表符(HT, 0x09)。
\v匹配 ASCII 垂直制表符(VT, 0x0B)。
\xhhhh匹配与十六进制数字hhhh(介于 0x0000 和 0xFFFF 之间)相对应的 Unicode 字符。
\0ooo(即0ooo)匹配八进制数字ooo(介于 0 和 0377 之间)的 ASCII/Latin1 字符。
.(点)匹配任何字符(包括换行符)。
\d匹配数字(QChar::isDigit ())。
\D匹配非数字。
\s匹配空格字符(QChar::isSpace())。
\S匹配非空格字符。
\w匹配单词字符(QChar::isLetterOrNumber(),QChar::isMark(), 或 '_')。
\W匹配非空格字符。
\n第 n 个反向参照,如 \1、\2 等。

注意:C++ 编译器会转换字符串中的反斜线。要将\包含在 regexp 中,请输入两次,即\\ 。要匹配反斜线字符本身,请输入四次,即\\\\

字符集

方括号表示匹配方括号中包含的任何字符。上述字符集缩写可以出现在方括号内的字符集中。除字符集缩写和以下两种例外情况外,字符在方括号中没有特殊含义。

^如果作为第一个字符(即紧接在开头的方括号之后)出现,则圆括号会否定字符集。[abc ]匹配 "a "或 "b "或 "c",而[^abc]匹配"a "或 "b "或 "c "以外的任何字符。
-破折号表示字符范围。[W-Z]匹配'W'或'X'或'Y'或'Z'。

使用预定义的字符集缩写比使用跨平台和跨语言的字符范围更具可移植性。例如,[0-9]匹配西方字母表中的数字,而\d则匹配任何字母表中的数字。

注意:在其他 regexp 文档中,字符集通常被称为 "字符类"。

数量词

默认情况下,表达式会自动用{1,1}进行量化,即表达式应恰好出现一次。在下面的列表中,E代表表达式。表达式是一个字符,或者是一组字符的缩写,或者是方括号中的一组字符,或者是括号中的表达式。

E?该量词表示前一个表达式是可选的,因为无论是否找到该表达式,它都将匹配。E?E{0,1} 相同。例如,dents?匹配 "dent "或 "dents"。
E+E+E{1,} 相同。例如,0 +与 "0"、"00"、"000 "等匹配。
E*E{0,} 相同。*量词经常被用在应该使用+的错误中。例如,如果在表达式中使用\s*$来匹配以空格结束的字符串,那么它将匹配每一个字符串,因为\s*$的意思是匹配字符串结束后的零个或多个空格。要匹配至少有一个尾部空白字符的字符串,正确的 regexp 是 \s+$。
E{n}E{n}等于重复E n次。例如,x{5}xxxxx 相同。它也与E{n,n} 相同,例如x{5,5}
E{n,}与至少n次出现的E 匹配。
E{,m}E{,m}E{0 ,m}相同。
E{n,m}至少匹配n 个且至多匹配m 个 E

要对前面的字符以外的字符使用量化符,可以使用括号将表达式中的字符组合在一起。例如,tag+会匹配一个 "t",然后是一个 "a "和至少一个 "g",而(tag)+则会匹配至少出现一次的 "tag"。

注意:数量词通常是 "贪婪的"。它们总是尽可能多地匹配文本。例如,0+会匹配找到的第一个 0 以及第一个 0 之后的所有连续 0。应用于 "20005 "时,它会匹配 "20005"。量词可以不贪心,请参见setMinimal()。

捕捉文本

括号允许我们将元素分组,以便量化和捕获它们。例如,如果我们的表达式mail|letter|correspondence与一个字符串匹配,我们知道其中一个词匹配,但不知道是哪个词。因此,如果我们使用(mail|letter|correspondence),并将此 regexp 与字符串 "我给你发了几封邮件 "匹配,我们就可以使用cap() 或capturedTexts() 函数提取匹配的字符,在本例中就是 "mail"。

我们可以在 regexp 本身中使用捕获的文本。要引用捕获的文本,我们可以使用反向引用,其索引从 1 开始,与cap() 相同。例如,我们可以使用 \b(\w+)\W+\1\b来搜索字符串中的重复单词,这意味着匹配一个单词边界,然后是一个或多个单词字符,接着是一个或多个非单词字符,然后是与第一个括号表达式相同的文本,最后是一个单词边界。

如果我们想将括号纯粹用于分组而不是捕获,我们可以使用非捕获语法,例如(?:green|blue) 。非捕捉括号以"(?: "开头,以") "结尾。在本例中,我们匹配了 "绿色 "或 "蓝色",但没有捕获匹配结果,因此我们只知道是否匹配,而不知道实际找到了哪种颜色。使用非捕获括号比使用捕获括号更有效率,因为 regexp 引擎需要做的记账工作更少。

捕获括号和非捕获括号都可以嵌套。

由于历史原因,适用于捕获括号的量词(如*)比其他量词更 "贪婪"。例如,a*(a*)将匹配 cap(1) == "aaa" 的 "aaa"。这种行为与其他 regexp 引擎(尤其是 Perl)不同。要获得更直观的捕获行为,请在 QRegExp 构造函数中指定QRegExp::RegExp2 或调用setPatternSyntax(QRegExp::RegExp2)。

当无法预先确定匹配次数时,一个常见的习惯做法是在循环中使用cap() 。例如

QRegExp rx("(\\d+)");
QString str = "Offsets: 12 14 99 231 7";
QStringList list;
int pos = 0;

while ((pos = rx.indexIn(str, pos)) != -1) {
    list << rx.cap(1);
    pos += rx.matchedLength();
}
// list: ["12", "14", "99", "231", "7"]

断言

断言在 regexp 中出现的地方对文本做出一些声明,但不匹配任何字符。在下面的列表中,E代表任意表达式。

^圆括号表示字符串的开头。如果要匹配字面^ ,则必须使用\\^ 来转义。例如,^#include 只匹配以 "#include "开头的字符串。(当刻度线是字符集的第一个字符时,它有特殊含义,参见Sets of Characters 。)
$美元表示字符串的结束。例如\d\s*$将匹配以数字结尾的字符串,这些数字后面可能还有空格。如果要匹配$ 的字面意思,必须使用\\$ 来转义。
\b单词边界。例如,重词表\bOK\b表示在一个单词边界(如字符串的开始或空白处)后立即匹配字母 "O",然后在另一个单词边界(如字符串的结束或空白处)前立即匹配字母 "K"。但是请注意,该断言实际上并不匹配任何空白,因此如果我们写下(\bOK\b),并且匹配成功,那么即使字符串是 "It'sOKnow",它也只包含 "OK"。
\B非单词边界。只要\b是假的,这个断言就是真的。例如,如果我们在 "Left on "中搜索 \Bon\B,匹配会失败(空格和字符串末尾不是非词边界),但在 "tonne"中会匹配。
(?=E)正向前瞻。如果表达式在 regexp 中的这一点上匹配,则该断言为真。例如,const(?=\s+char)在 "staticconstchar *"中,只要 "const "后面有 "char",就会匹配 "const"。(与const\s+char 相比,它匹配的是 "staticconst char*")。
(?!E)负前瞻性。如果表达式在 regexp 中不匹配,则该断言为真。例如,const(?!\s+char)与 "const "匹配,除非后面跟了 "char"。

通配符匹配

大多数命令 shell(如bashcmd.exe)都支持 "文件选取"(file globbing),即使用通配符识别一组文件的能力。setPatternSyntax() 函数用于在 regexp 和通配符模式之间切换。通配符匹配比完整的 regexp 简单得多,只有四种功能:

c除下面提到的字符外,任何字符都代表自己。因此,c匹配字符c
?匹配任何单个字符。它与完整 regexps 中的.相同。
*匹配零个或多个任意字符。它与完整 regexps 中的.*相同。
[...]字符集可以用方括号表示,与完整 regexps 类似。在字符类内,反斜线与字符类外一样,没有特殊含义。

在通配符模式下,通配符不能转义。在WildcardUnix 模式下,字符"\"可以转义通配符。

例如,在通配符模式下,如果字符串包含文件名,我们可以用*.html 来识别 HTML 文件。这将匹配零个或多个点后跟'h'、't'、'm'和'l'的字符。

要根据通配符表达式测试字符串,请使用exactMatch()。例如

QRegExp rx("*.txt");
rx.setPatternSyntax(QRegExp::Wildcard);
rx.exactMatch("README.txt");        // returns true
rx.exactMatch("welcome.txt.bak");   // returns false

Perl 用户须知

QRegExp 支持 Perl 支持的大多数字符类缩写,请参见characters and abbreviations for sets of characters

在 QRegExp 中,除了在字符类中,^ 总是表示字符串的开始,因此,除非用于该目的,否则必须总是转义符。在 Perl 中,字符间距的含义会根据其出现的位置自动变化,因此很少需要转义。$ 也是如此,它在 QRegExp 中总是表示字符串的结束。

QRegExp 的量词与 Perl 的贪婪量词相同(但请参见note above )。非贪婪匹配不能应用于单个量化符,但可以应用于模式中的所有量化符。例如,要匹配 Perl regexpro+?m需要:

QRegExp rx("ro+m");
rx.setMinimal(true);

与 Perl 的/i 选项等价的是setCaseSensitivity(Qt::CaseInsensitive)。

Perl 的/g 选项可以用loop 来模拟。

在 QRegExp 中,.匹配任何字符,因此所有 QRegExp regexp 都与 Perl 的/s 选项等价。QRegExp 没有与 Perl 的/m 选项等效的选项,但可以用各种方法来模拟,例如将输入内容分成几行,或使用一个循环的 regexp 来搜索换行符。

由于 QRegExp 是面向字符串的,因此没有 \A、\Z 或 \z 断言。不支持 \G 断言,但可以在循环中模拟。

Perl 的 $& 是 cap(0) 或capturedTexts()[0] 。没有与 $`、$' 或 $+ 对应的 QRegExp。Perl 的捕获变量 $1, $2, ...对应 cap(1) 或capturedTexts()[1], cap(2) 或capturedTexts()[2] 等。

要替换模式,请使用QString::replace() 。

不支持 Perl 的扩展/x 语法,也不支持指令,例如 (?i) 或 regexp 注释,例如 (?#comment) 。另一方面,可以使用 C++ 的字面字符串规则来实现同样的目的:

QRegExp mark("\\b"      // word boundary
              "[Mm]ark" // the word we want to match
            );

零宽度正向和零宽度负向前瞻断言 (?=pattern) 和 (?!pattern) 都支持,语法与 Perl 相同。不支持 Perl 的前瞻断言、"独立 "子表达式和条件表达式。

还支持非捕获括号,语法与 Perl 的 (?:pattern) 相同。

请参见QString::split() 和QStringList::join() 以了解与 Perl 的 split 和 join 函数的对应关系。

注意:由于 C++ 对 \'s 进行了转换,它们必须在代码中写两次,例如\b必须写成\\b。

代码示例

QRegExp rx("^\\d\\d?$");    // match integers 0 to 99
rx.indexIn("123");          // returns -1 (no match)
rx.indexIn("-6");           // returns -1 (no match)
rx.indexIn("6");            // returns 0 (matched at position 0)

第三个字符串匹配"6"。这是一个简单的验证 regexp,适用于 0 至 99 范围内的整数。

QRegExp rx("^\\S+$");       // match strings without whitespace
rx.indexIn("Hello world");  // returns -1 (no match)
rx.indexIn("This_is-OK");   // returns 0 (matched at position 0)

第二个字符串匹配"This_is-OK"。我们使用了字符集缩写"\S"(非空格)和锚来匹配不包含空格的字符串。

在下面的示例中,我们匹配包含 "mail"、"letter "或 "respondence "的字符串,但只匹配整个单词,即不匹配 "email"。

QRegExp rx("\\b(mail|letter|correspondence)\\b");
rx.indexIn("I sent you an email");     // returns -1 (no match)
rx.indexIn("Please write the letter"); // returns 17

第二个字符串匹配 "请写信"。信件 "一词也被捕获(因为有括号)。我们可以看到我们捕获的文本是这样的

QString captured = rx.cap(1); // captured == "letter"

这将捕获第一组捕获括号中的文本(从左到右计算捕获左括号)。由于 cap(0) 是整个匹配的 regexp(相当于大多数 regexp 引擎中的"&"),所以括号是从 1 开始计算的。

QRegExp rx("&(?!amp;)");      // match ampersands but not &amp;
QString line1 = "This & that";
line1.replace(rx, "&amp;");
// line1 == "This &amp; that"
QString line2 = "His &amp; hers & theirs";
line2.replace(rx, "&amp;");
// line2 == "His &amp; hers &amp; theirs"

在这里,我们将 QRegExp 传递给QString 的 replace() 函数,用新文本替换匹配的文本。

QString str = "One Eric another Eirik, and an Ericsson. "
              "How many Eiriks, Eric?";
QRegExp rx("\\b(Eric|Eirik)\\b"); // match Eric or Eirik
int pos = 0;    // where we are in the string
int count = 0;  // how many Eric and Eirik's we've counted
while (pos >= 0) {
    pos = rx.indexIn(str, pos);
    if (pos >= 0) {
        ++pos;      // move along in str
        ++count;    // count our Eric or Eirik
    }
}

我们使用indexIn() 函数重复匹配字符串中的 regexp。请注意,我们本可以写pos += rx.matchedLength() 来跳过已经匹配的字符串,而不是每次向前移动一个字符pos++ 。计数将等于 3,匹配 "一个Eric,另一个Eirik,还有一个 Ericsson。有多少个 Eiriks,Eric?";它不匹配 "Ericsson "或 "Eiriks",因为它们没有非单词边界。

regexps 的一个常见用法是将分隔数据行分割成其组成字段。

str = "The Qt Company Ltd\tqt.io\tFinland";
QString company, web, country;
rx.setPattern("^([^\t]+)\t([^\t]+)\t([^\t]+)$");
if (rx.indexIn(str) != -1) {
    company = rx.cap(1);
    web = rx.cap(2);
    country = rx.cap(3);
}

在本例中,我们的输入行格式为公司名称、网址和国家。遗憾的是,这个 regexp 相当长,而且用途不广--如果我们添加更多的字段,代码就会中断。一个更简单、更好的解决方案是查找分隔符,在本例中为"\t",然后获取周围的文本。QString::split() 函数可以将分隔符字符串或 regexp 作为参数,并据此分割字符串。

QStringList field = str.split("\t");

这里,field[0] 是公司,field[1] 是网址,以此类推。

为了模仿 shell 的匹配方式,我们可以使用通配符模式。

QRegExp rx("*.html");
rx.setPatternSyntax(QRegExp::Wildcard);
rx.exactMatch("index.html");                // returns true
rx.exactMatch("default.htm");               // returns false
rx.exactMatch("readme.txt");                // returns false

通配符匹配因其简单而方便,但任何通配符 regexp 都可以使用完整的 regexp 来定义,例如.*\.html$。请注意,我们不能用通配符同时匹配.html.htm 两个文件,除非使用*.htm*,这样也能匹配 "test.html.bak"。完整的 regexp 可以提供我们需要的精确度,即.*\.html?$

QRegExp 可以使用setCaseSensitivity() 进行大小写不敏感匹配,也可以使用非贪婪匹配,参见setMinimal() 。QRegExp 默认使用完全重词法,但可以通过setPatternSyntax() 进行更改。搜索可以通过indexIn() 向前进行,也可以通过lastIndexIn() 向后进行。可以使用capturedTexts() 或cap() 访问捕获的文本,前者返回所有捕获字符串的字符串列表,后者返回给定索引的捕获字符串。pos() 函数接收匹配索引,并返回字符串中进行匹配的位置(如果没有匹配,则返回-1)。

移植到 QRegularExpression

Qt 5 中引入的QRegularExpression 类实现了与 Perl 兼容的正则表达式,在提供的 API、支持的模式语法和执行速度方面都比 QRegExp 有了很大改进。与 QRegExp 最大的不同是,QRegularExpression 只保存正则表达式,在请求匹配时不会修改正则表达式。相反,它会返回一个QRegularExpressionMatch 对象,用于检查匹配结果并提取捕获的子串。全局匹配和QRegularExpressionMatchIterator 也是如此。

其他区别概述如下。

注意: QRegularExpression 并不支持与 Perl 兼容的正则表达式中的所有功能。最值得注意的是,它不支持捕获组的重复名称,使用它们会导致未定义的行为。这可能会在 Qt 的未来版本中有所改变。

不同的模式语法

将正则表达式从 QRegExp 移植到QRegularExpression 可能需要更改模式本身。

在特定情况下,QRegExp 过于宽松,接受的模式在使用QRegularExpression 时根本无效。这种情况很容易发现,因为使用这些模式构建的QRegularExpression 对象是无效的(参见QRegularExpression::isValid())。

在其他情况下,从 QRegExp 移植到QRegularExpression 的模式可能会悄悄改变语义。因此,有必要对所使用的模式进行审查。最明显的静默不兼容情况是

  • 使用像\xHHHH 这样超过 2 位数的十六进制转义符时需要使用大括号。像\x2022 这样的模式需要移植到\x{2022} ,否则它将匹配空格 (0x20) 后的字符串"22" 。一般来说,强烈建议始终使用带大括号的\x 转义符,无论指定的位数是多少。
  • {,n} 这样从 0 到 n 的量化需要移植到{0,n} 以保留语义。否则,像\d{,3} 这样的模式将匹配一个数字后的精确字符串"{,3}"
  • QRegExp 默认进行 Unicode 感知匹配,而QRegularExpression 则需要一个单独的选项;详情见下文。
  • QRegExp 中的 c{.} 默认匹配所有字符,包括换行符。QRegularExpression 默认不匹配换行符。要包含换行符,请设置QRegularExpression::DotMatchesEverythingOption pattern 选项。

有关QRegularExpression 支持的正则表达式语法概览,请参阅pcrepattern(3)man 页面,其中介绍了 PCRE(Perl 兼容正则表达式的参考实现)支持的模式语法。

从 QRegExp::exactMatch() 移植

QRegExp::exactMatch()有两个作用:将正则表达式与主题字符串进行精确匹配,以及实现部分匹配。

从 QRegExp 的精确匹配移植而来

精确匹配表示正则表达式是否匹配整个主题字符串。例如,在主题字符串"abc123" 上生成的类:

QRegExp::exactMatch()QRegularExpressionMatch::hasMatch()
"\\d+"true
"[a-z]+\\d+"truetrue

QRegularExpression 中不反映精确匹配。如果要确保主题字符串与正则表达式完全匹配,可以使用QRegularExpression::anchoredPattern() 函数对模式进行包装:

QString p("a .*|pattern");

// re matches exactly the pattern string p
QRegularExpression re(QRegularExpression::anchoredPattern(p));
从 QRegExp 的部分匹配移植过来

在使用QRegExp::exactMatch() 时,如果没有找到完全匹配的正则表达式,还可以通过调用QRegExp::matchedLength() 找出主题字符串中有多少部分与正则表达式匹配。如果返回的长度等于主题字符串的长度,那么就可以断定找到了部分匹配。

QRegularExpression 正则表达式 明确支持部分匹配。QRegularExpression::MatchType

全局匹配

由于 QRegExp API 的限制,无法正确实现全局匹配(即像 Perl 那样)。特别是可以匹配 0 个字符的模式(如"a*" )会有问题。

QRegularExpression::globalMatch() 可以正确实现 Perl 全局匹配,返回的迭代器可用于检查每个结果。

例如

QString subject("the quick fox");

int offset = 0;
QRegExp re("(\\w+)");
while ((offset = re.indexIn(subject, offset)) != -1) {
    offset += re.matchedLength();
    // ...
}

可以重写为

QString subject("the quick fox");

QRegularExpression re("(\\w+)");
QRegularExpressionMatchIterator i = re.globalMatch(subject);
while (i.hasNext()) {
    QRegularExpressionMatch match = i.next();
    // ...
}
支持 Unicode 属性

使用 QRegExp 时,字符类(如\w,\d 等)会匹配具有相应 Unicode 属性的字符:例如,\d 会匹配任何具有 UnicodeNd (十进制数字)属性的字符。

使用QRegularExpression 时,这些字符类默认只匹配 ASCII 字符:例如,\d 完全匹配0-9 ASCII 范围内的字符。使用QRegularExpression::UseUnicodePropertiesOption 模式选项可以改变这种行为。

通配符匹配

QRegularExpression 中没有直接进行通配符匹配的方法。不过,我们提供了QRegularExpression::wildcardToRegularExpression() 方法,用于将 glob 模式转换为与 Perl 兼容的正则表达式。

例如,如果您有如下代码

QRegExp wildcard("*.txt");
wildcard.setPatternSyntax(QRegExp::Wildcard);

可以重写为

auto wildcard = QRegularExpression(QRegularExpression::wildcardToRegularExpression("*.txt"));

但请注意,某些类似 shell 的通配符模式可能无法转换成您所期望的结果。如果使用上述函数进行简单转换,下面的示例代码就会自动中断:

const QString fp1("C:/Users/dummy/files/content.txt");
const QString fp2("/home/dummy/files/content.txt");

QRegExp re1("*/files/*");
re1.setPatternSyntax(QRegExp::Wildcard);
re1.exactMatch(fp1); // returns true
re1.exactMatch(fp2); // returns true

// but converted with QRegularExpression::wildcardToRegularExpression()

QRegularExpression re2(QRegularExpression::wildcardToRegularExpression("*/files/*"));
re2.match(fp1).hasMatch(); // returns false
re2.match(fp2).hasMatch(); // returns false

这是因为,默认情况下,QRegularExpression::wildcardToRegularExpression() 返回的正则表达式是完全锚定的。要获得非锚定的正则表达式,请在转换选项中输入QRegularExpression::UnanchoredWildcardConversion

QRegularExpression re3(QRegularExpression::wildcardToRegularExpression(
                           "*/files/*", QRegularExpression::UnanchoredWildcardConversion));
re3.match(fp1).hasMatch(); // returns true
re3.match(fp2).hasMatch(); // returns true
最小匹配

QRegExp::setMinimal(QRegExp () 通过简单地反转量词的贪婪程度来实现最小匹配(QRegExp 不支持懒量词,如*?,+? 等)。QRegularExpression 支持贪婪、懒和所有格量词。QRegularExpression::InvertedGreedinessOption 模式选项可以用来模拟QRegExp::setMinimal() 的效果:如果启用,它可以反转量词的贪婪程度(贪婪的量词变成懒惰的,反之亦然)。

粗心模式

QRegularExpression::AnchorAtOffsetMatchOption match 选项可用于模拟QRegExp::CaretAtOffset 的行为。其他QRegExp::CaretMode 模式没有类似的功能。

另请参见 QString,QStringList, 和QSortFilterProxyModel

成员类型文档

enum QRegExp::CaretMode

CaretMode 枚举定义了正则表达式中护理符号(^) 的不同含义。可能的值有

常量说明
QRegExp::CaretAtZero0圆点对应于搜索字符串中的索引 0。
QRegExp::CaretAtOffset1空格对应搜索的起始偏移量。
QRegExp::CaretWontMatch2字符间距永远不会匹配。

enum QRegExp::PatternSyntax

用于解释模式含义的语法。

常量说明
QRegExp::RegExp0类似 Perl 的丰富模式匹配语法。这是默认值。
QRegExp::RegExp23类似 RegExp,但使用greedy quantifiers 。(在 Qt XML 4.2 中引入。)
QRegExp::Wildcard1这提供了一种简单的模式匹配语法,类似于 shell(命令解释器)用于 "文件选取"(file globbing)的模式匹配语法。参见QRegExp wildcard matching
QRegExp::WildcardUnix4这与通配符类似,但具有 Unix shell 的行为。通配符可以用字符"\"转义。
QRegExp::FixedString2模式是一个固定的字符串。这等同于在字符串上使用 RegExp 模式,其中所有元字符都使用escape() 转义。
QRegExp::W3CXmlSchema115该模式是 W3C XML Schema 1.1 规范定义的正则表达式。

另请参阅 setPatternSyntax()。

成员函数文档

QRegExp::QRegExp()

构造空 regexp。

另请参阅 isValid() 和errorString()。

[explicit] QRegExp::QRegExp(const QString &pattern, Qt::CaseSensitivity cs = Qt::CaseSensitive, QRegExp::PatternSyntax syntax = RegExp)

为给定的pattern 字符串构造正则表达式对象。如果syntaxWildcard ,则必须使用通配符给出模式;默认值是RegExp 。模式区分大小写,除非csQt::CaseInsensitive 。匹配是贪婪的(最大值),但可以通过调用setMinimal() 进行更改。

另请参见 setPattern()、setCaseSensitivity() 和setPatternSyntax()。

QRegExp::QRegExp(const QRegExp &rx)

构造正则表达式,作为rx 的副本。

另请参见 operator=().

[noexcept] QRegExp::~QRegExp()

销毁正则表达式并清理其内部数据。

QString QRegExp::cap(int nth = 0) const

返回nth 子表达式捕获的文本。整个匹配的索引为 0,括号中的子表达式的索引从 1 开始(不包括未捕获的括号)。

QRegExp rxlen("(\\d+)(?:\\s*)(cm|inch)");
int pos = rxlen.indexIn("Length: 189cm");
if (pos > -1) {
    QString value = rxlen.cap(1); // "189"
    QString unit = rxlen.cap(2);  // "cm"
    // ...
}

由 cap() 匹配的元素顺序如下。第一个元素 cap(0) 是整个匹配字符串。随后的每个元素都与下一个捕获的左开括号相对应。因此,cap(1) 是第一个捕捉括号的文本,cap(2) 是第二个捕捉括号的文本,依此类推。

另请参见 capturedTexts() 和pos()。

int QRegExp::captureCount() const

返回正则表达式中包含的捕获数。

QStringList QRegExp::capturedTexts() const

返回捕获的文本字符串列表。

列表中的第一个字符串是整个匹配字符串。随后的每个列表元素都包含与 regexp 的一个(捕获)子表达式匹配的字符串。

例如

QRegExp rx("(\\d+)(\\s*)(cm|inch(es)?)");
int pos = rx.indexIn("Length: 36 inches");
QStringList list = rx.capturedTexts();
// list is now ("36 inches", "36", " ", "inches", "es")

上述示例还捕获了可能存在但我们不感兴趣的元素。这个问题可以通过使用非捕获括号来解决:

QRegExp rx("(\\d+)(?:\\s*)(cm|inch(?:es)?)");
int pos = rx.indexIn("Length: 36 inches");
QStringList list = rx.capturedTexts();
// list is now ("36 inches", "36", "inches")

注意,如果要遍历列表,应遍历副本,例如

QStringList list = rx.capturedTexts();
QStringList::iterator it = list.begin();
while (it != list.end()) {
    myProcessing(*it);
    ++it;
}

有些 regexp 可以匹配不确定的次数。例如,如果输入字符串是 "Offsets: 12 14 99 231 7",而 regexprx(\d+)+,我们希望得到一个包含所有匹配数字的列表。但是,在调用rx.indexIn(str) 后,capturedTexts() 将返回列表("12", "12"),即整个匹配结果是 "12",第一个匹配的子表达式是 "12"。正确的做法是在loop 中使用cap() 。

字符串列表中元素的顺序如下。第一个元素是整个匹配字符串。随后的每个元素对应于下一个捕获打开的左括号。因此,capturedTexts()[1] 是第一个捕获括号的文本,capturedTexts()[2] 是第二个捕获括号的文本,以此类推(在其他一些 regexp 语言中对应于 $1, $2 等)。

另请参见 cap() 和pos()。

Qt::CaseSensitivity QRegExp::caseSensitivity() const

如果 regexp 按大小写匹配,则返回Qt::CaseSensitive ;否则返回Qt::CaseInsensitive

另请参见 setCaseSensitivity()、patternSyntax()、pattern() 和isMinimal()。

int QRegExp::countIn(const QString &str) const

返回str 中该正则表达式的匹配次数。

另请参阅 indexIn()、lastIndexIn() 和replaceIn()。

QString QRegExp::errorString() const

返回一个文本字符串,解释 regexp 模式无效的原因;否则返回 "无错误发生"。

另请参见 isValid()。

[static] QString QRegExp::escape(const QString &str)

返回str 字符串,其中每个 regexp 特殊字符都用反斜杠转义。特殊字符包括 $, (,), *, +, ., ?, [, ,], ^, {, | 和 }。

示例

s1 = QRegExp::escape("bingo");   // s1 == "bingo"
s2 = QRegExp::escape("f(x)");    // s2 == "f\\(x\\)"

该函数用于动态构建 regexp 模式:

QRegExp rx("(" + QRegExp::escape(name) +
           "|" + QRegExp::escape(alias) + ")");

另请参阅 setPatternSyntax().

bool QRegExp::exactMatch(const QString &str) const

如果str 与此正则表达式完全匹配,则返回true ;否则返回false 。您可以通过调用matchedLength() 来确定有多少字符串被匹配。

对于给定的正则表达式字符串 R,exactMatch("R") 等同于indexIn("^R$") ,因为 exactMatch() 有效地将正则表达式包围在字符串开始和字符串结束的锚点中,只是对matchedLength() 的设置不同。

例如,如果正则表达式为蓝色,那么 exactMatch() 只会在输入blue 时返回true 。对于输入bluebellblutaklightblue ,exactMatch( ) 将返回false ,而matchedLength() 将分别返回 4、3 和 0。

虽然是常量,但此函数会设置matchedLength()、capturedTexts() 和pos()。

另请参见 indexIn() 和lastIndexIn()。

QStringList QRegExp::filterList(const QStringList &stringList) const

返回stringList 中与此正则表达式匹配的所有字符串的列表。

int QRegExp::indexIn(const QStringList &list, int from) const

返回list 中该 regexp 第一个完全匹配项的索引位置,从索引位置from 开始向前搜索。如果没有匹配项,则返回-1。

另请参阅 lastIndexIn() 和exactMatch()。

int QRegExp::indexIn(const QString &str, int offset = 0, QRegExp::CaretMode caretMode = CaretAtZero) const

尝试在str 中查找从offset (默认为 0)位置开始的匹配项。如果offset 为-1,则从最后一个字符开始搜索;如果为-2,则从次最后一个字符开始搜索;等等。

返回第一个匹配字符的位置,如果没有匹配字符,则返回-1。

caretMode 参数可用于指示^应从索引 0 还是offset 开始匹配。

您可能更喜欢使用QString::indexOf()、QString::contains() 甚至QStringList::filter()。要替换匹配结果,请使用QString::replace() 。

示例:

QString str = "offsets: 1.23 .50 71.00 6.00";
QRegExp rx("\\d*\\.\\d+");    // primitive floating point matching
int count = 0;
int pos = 0;
while ((pos = rx.indexIn(str, pos)) != -1) {
    ++count;
    pos += rx.matchedLength();
}
// pos will be 9, 14, 18 and finally 24; count will end up as 4

虽然是常量,但该函数设置了matchedLength(),capturedTexts() 和pos().

如果QRegExp 是一个通配符表达式(参见setPatternSyntax()) 并希望根据整个通配符表达式测试字符串,请使用exactMatch() 代替此函数。

另请参见 lastIndexIn() 和exactMatch()。

bool QRegExp::isEmpty() const

如果模式字符串为空,则返回true ;否则返回 false。

如果在空字符串上使用空模式调用exactMatch() 将返回 true,否则将返回false ,因为它对整个字符串进行操作。如果在任何字符串上调用indexIn() 并使用空模式,将返回起始偏移量(默认为 0),因为空模式与字符串起始处的 "空 "相匹配。在这种情况下,matchedLength() 返回的匹配长度将为 0。

参见QString::isEmpty()。

bool QRegExp::isMinimal() const

如果启用了最小(非贪婪)匹配,则返回true ;否则返回false

另请参见 caseSensitivity() 和setMinimal()。

bool QRegExp::isValid() const

如果正则表达式有效,则返回true ;否则返回 false。无效的正则表达式永远不会匹配。

模式[a-z是无效模式的一个例子,因为它缺少结尾方括号。

请注意,正则表达式的有效性也可能取决于通配符标志的设置,例如*.html是一个有效的通配符正则表达式,但却是一个无效的完整正则表达式。

另请参见 errorString()。

int QRegExp::lastIndexIn(const QStringList &list, int from) const

返回list 中最后一个与此 regexp 完全匹配的索引位置,从索引位置from 开始向后搜索。如果from 为 -1(默认值),则从最后一项开始搜索。如果没有匹配项,则返回-1。

另请参见 QRegExp::exactMatch().

int QRegExp::lastIndexIn(const QString &str, int offset = -1, QRegExp::CaretMode caretMode = CaretAtZero) const

尝试在str 中从offset 位置向后查找匹配字符。如果offset 为-1(默认值),则从最后一个字符开始搜索;如果为-2,则从次最后一个字符开始搜索;等等。

返回第一个匹配字符的位置,如果没有匹配字符,则返回-1。

caretMode 参数可用于指示^应从索引 0 还是offset 开始匹配。

虽然是常量,但该函数会设置matchedLength()、capturedTexts() 和pos()。

警告: 向后搜索比向前搜索要慢得多。

另请参阅 indexIn() 和exactMatch()。

int QRegExp::matchedLength() const

返回最后匹配字符串的长度,如果没有匹配,则返回-1。

另请参阅 exactMatch()、indexIn() 和lastIndexIn()。

QString QRegExp::pattern() const

返回正则表达式的模式字符串。模式有正则表达式语法或通配符语法,具体取决于patternSyntax()。

另请参阅 setPattern()、patternSyntax() 和caseSensitivity()。

QRegExp::PatternSyntax QRegExp::patternSyntax() const

返回正则表达式使用的语法。默认值为QRegExp::RegExp

另请参阅 setPatternSyntax()、pattern() 和caseSensitivity()。

int QRegExp::pos(int nth = 0) const

返回nth 捕捉到的文本在搜索字符串中的位置。如果nth 为 0(默认值),则 pos() 返回整个匹配的位置。

举例说明:

QRegExp rx("/([a-z]+)/([a-z]+)");
rx.indexIn("Output /dev/null");   // returns 7 (position of /dev/null)
rx.pos(0);                        // returns 7 (position of /dev/null)
rx.pos(1);                        // returns 8 (position of dev)
rx.pos(2);                        // returns 12 (position of null)

例如,如果 cap(4) 返回空字符串,则 pos(4) 返回-1。这是实现的一个特点。

另请参阅 cap() 和capturedTexts()。

QString QRegExp::removeIn(const QString &str) const

删除str 中出现的每一个正则表达式,并返回结果

replaceIn(str, QString()) 的功能相同。

另请参阅 indexIn(),lastIndexIn() 和replaceIn()。

QString QRegExp::replaceIn(const QString &str, const QString &after) const

after 替换str 中出现的每一个正则表达式,并返回结果。

对于包含capturing parentheses 的正则表达式,after 中出现的\1、\2、...将被替换为rx.cap(1), cap(2), ...。

另请参见 indexIn()、lastIndexIn() 和QRegExp::cap()。

QStringList QRegExp::replaceIn(const QStringList &stringList, const QString &after) const

after 替换stringList's 中出现的每一个 regexp。返回字符串列表的引用。

void QRegExp::setCaseSensitivity(Qt::CaseSensitivity cs)

将大小写敏感匹配设置为cs

如果csQt::CaseSensitive ,则 \.txt$匹配readme.txt ,但不匹配README.TXT

另请参见 caseSensitivity()、setPatternSyntax()、setPattern() 和setMinimal()。

void QRegExp::setMinimal(bool minimal)

启用或禁用最小匹配。如果minimal 为 false,则默认使用贪婪(最大)匹配。

例如,假设输入字符串为 "We must be <b>bold</b>, very <b>bold</b>!" 和模式<b>.*</b>。使用默认的贪婪(最大)匹配,匹配结果是 "We must be<b>bold</b>, very <b>bold</b>!但如果使用最小匹配(非贪婪匹配),则第一个匹配结果是"我们必须<b>粗体</b>,非常<b>粗体</b>!",第二个匹配是 "我们必须<b>粗体</b>,非常<b>粗体</b>!"。在实践中,我们可以使用模式<b>[^<]*</b>来代替,不过这仍然会导致嵌套标记失败。

另请参见 isMinimal() 和setCaseSensitivity()。

void QRegExp::setPattern(const QString &pattern)

将模式字符串设置为pattern 。大小写敏感性、通配符和最小匹配选项不变。

另请参阅 pattern()、setPatternSyntax() 和setCaseSensitivity()。

void QRegExp::setPatternSyntax(QRegExp::PatternSyntax syntax)

设置正则表达式的语法模式。默认为QRegExp::RegExp

syntax 设置为QRegExp::Wildcard 可启用类似于 shell 的简单QRegExp wildcard matching 。例如,r*.txt匹配通配符模式下的字符串readme.txt ,但不匹配readme

syntax 设置为QRegExp::FixedString 意味着模式被解释为普通字符串。此时,特殊字符(如反斜杠)无需转义。

另请参阅 patternSyntax()、setPattern()、setCaseSensitivity() 和escape()。

QStringList QRegExp::splitString(const QString &str, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const

str 拆分为与正则表达式匹配的子串,并返回这些字符串的列表。如果该正则表达式未在字符串中的任何位置匹配,则 split() 返回一个包含str 的单元素列表。

如果behavior 设置为Qt::KeepEmptyParts ,则空字段将包含在生成的列表中。

另请参阅 QStringList::join() 和QString::split()。

[noexcept] void QRegExp::swap(QRegExp &other)

将正则表达式other 与此正则表达式互换。该操作速度非常快,而且从不出错。

QVariant QRegExp::operator QVariant() const

QVariant

bool QRegExp::operator!=(const QRegExp &rx) const

如果该正则表达式不等于rx ,则返回true ;否则返回false

另请参见 operator==().

[noexcept] QRegExp &QRegExp::operator=(QRegExp &&other)

Move-assignsother 到此QRegExp 实例。

QRegExp &QRegExp::operator=(const QRegExp &rx)

复制正则表达式rx 并返回副本的引用。大小写敏感性、通配符和最小匹配选项也会被复制。

bool QRegExp::operator==(const QRegExp &rx) const

如果该正则表达式等于rx ,则返回true ;否则返回false

如果两个QRegExp 对象具有相同的模式字符串以及相同的大小写敏感性、通配符和最小匹配设置,则这两个对象是相等的。

相关非成员

[noexcept] size_t qHash(const QRegExp &key, size_t seed = 0)

返回key 的哈希值,使用seed 作为计算的种子。

QDataStream &operator<<(QDataStream &out, const QRegExp &regExp)

将正则表达式regExp 写入流out

另请参阅 序列化 Qt 数据类型

QDataStream &operator>>(QDataStream &in, QRegExp &regExp)

将正则表达式从流in 读入regExp

另请参阅 序列化 Qt 数据类型

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.