QRegExp 类

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

头文件 #include <QRegExp>
CMakefind_package(Qt6 REQUIRED COMPONENTS Core5Compat)
target_link_libraries(mytarget PRIVATE Qt6::Core5Compat)
qmakeQT += core5compat

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

公共类型

枚举CaretMode { CaretAtZero, CaretAtOffset, CaretWontMatch }
枚举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()
QStringcap(int nth = 0) const
intcaptureCount() const
QStringListcapturedTexts() const
Qt::CaseSensitivitycaseSensitivity() const
intcountIn(const QString &str) const
QStringerrorString() const
boolexactMatch(const QString &str) const
QStringListfilterList(const QStringList &stringList) const
intindexIn(const QString &str, int offset = 0, QRegExp::CaretMode caretMode = CaretAtZero) const
intindexIn(const QStringList &list, int from) const
boolisEmpty() const
boolisMinimal() const
boolisValid() const
intlastIndexIn(const QString &str, int offset = -1, QRegExp::CaretMode caretMode = CaretAtZero) const
intlastIndexIn(const QStringList &list, int from) const
intmatchedLength() const
QStringpattern() const
QRegExp::PatternSyntaxpatternSyntax() const
intpos(int nth = 0) const
QStringremoveIn(const QString &str) const
QStringreplaceIn(const QString &str, const QString &after) const
QStringListreplaceIn(const QStringList &stringList, const QString &after) const
void设置大小写敏感度(Qt::CaseSensitivity cs)
void设置为最小化(bool minimal)
void设置模式(const QString &pattern)
void设置模式语法(QRegExp::PatternSyntax syntax)
QStringList拆分字符串(const QString &str, Qt::SplitBehavior behavior = Qt::KeepEmptyParts) const
void交换(QRegExp &other)
QVariant转换为QVariant() const
bool不等(const QRegExp &rx) const
QRegExp &赋值(const QRegExp &rx)
QRegExp &赋值(QRegExp &&other)
bool等于(const QRegExp &rx) const

静态公有成员

QString转义(const QString &str)
size_tqHash(const QRegExp &key, size_t seed = 0)
QDataStream &插入流操作符(QDataStream &out, const QRegExp &regExp)
QDataStream &提取流操作符(QDataStream &in, QRegExp &regExp)

详细说明

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

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

验证正则表达式可以测试一个子串是否满足某些条件,例如,它是一个整数或不包含空白字符。
搜索正则表达式提供的模式匹配比简单的子串匹配更强大,例如,匹配一个单词 maillettercorrespondence,但不能匹配单词 emailmailmanmailerletterbox 等。
搜索和替换正则表达式可以将所有出现的子串替换为不同的子串,例如,将所有出现的 & 替换为 &amp;,除了 & 已经跟随一个 amp; 的情况下。
字符串拆分正则表达式可以用来确定在哪里可以拆分字符串,例如,拆分制表符分隔的字符串。

以下是对正则表达式的一个简要介绍,Qt的正则表达式语言描述,一些示例以及该函数的文档。QRegExp模仿Perl的正则表达式语言。它完全支持Unicode。QRegExp 还可以在一种更简单的 通配符模式 下使用,类似于在命令 Shell 中找到的功能。QRegExp使用的语法规则可以通过setPatternSyntax() 进行更改。特别地,模式语法可以设置为QRegExp::FixedString,这意味着要匹配的模式按普通字符串解释,即特殊字符(例如反斜杠)无需转义。

一本关于正则表达式的好书是 Jeffrey E. F. Friedl 撰写的《精通正则表达式》(第三版),ISBN 0-596-52812-4。

注意: 在 Qt 5 中,新的 QRegularExpression 类提供了与 Perl 兼容的正则表达式实现,并被推荐用于 QRegExp 的替代品。

简介

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

量词指定了表达式必须匹配出现的次数。 x{1,1} 表示匹配一个并且仅有一个 xx{1,5} 表示匹配包含至少一个 x 但不超过五个 x 的字符序列。

请注意,一般而言,正则表达式不能用来检查括号或标签是否平衡。例如,可以编写一个正则表达式来匹配非嵌套的 <$b> 开头标签和它的闭合标签 </b>,但是,如果 <$b> 标签是嵌套的,那么相同的正则表达式将匹配错误闭合的 <$b> 标签。对于片段 <$b>bold <b>bolder</b></b>,第一个 <$b> 将与第一个 </b> 匹配,这是不正确的。然而,可以编写一个正则表达式来正确匹配嵌套的括号或标签,但只有当嵌套级别是固定和已知的情况下才可能。如果嵌套级别不是固定和已知的,则无法编写一个不会失败的正则表达式。

假设我们希望一个正则表达式匹配0到99范围内的整数。至少需要一个数字,所以我们从表达式 [0-9]{1,1} 开始,它可以精确匹配单个数字一次。这个正则表达式匹配0到9范围内的整数。为了匹配到99的整数,增加最大匹配次数到2,那么正则表达式就变成了 [0-9]{1,2}。这个正则表达式满足了匹配从0到99的原始要求,但它也会匹配字符串中间出现的整数。如果我们希望匹配到的整数是整个字符串,我们必须使用锚点断言,^(标记)和 $(美元)。当 ^ 是正则表达式的第一个字符时,它意味着正则表达式必须从字符串的开头匹配。当 $ 是正则表达式的最后一个字符时,它意味着正则表达式必须匹配到字符串的末尾。正则表达式变为 ^[0-9]{1,2}$。注意,断言,例如 ^$,不匹配字符,而是匹配字符串中的位置。

如果您在其他地方见过正则表达式的描述,它们可能看起来与这里的不同。这是因为某些字符集和一些量词非常常见,因此已赋予它们特殊的符号来表示。例如 [0-9] 可以被符号 \d 替换。匹配恰好一次出现的量词 {1,1} 可以被表达式本身替换,即 x{1,1}x 相同。因此,0到99的匹配器可以写成 ^\d{1,2}$。也可以写作 ^\d\d{0,1}$,即 从字符串开头,匹配一个数字,后面紧接着是0或1个数字。在实际应用中,它会被写作 ^\d\d?$。这里的 ? 是量词 {0,1} 的简写,即0或1次出现。? 使表达式成为可选的。正则表达式 ^\d\d?$ 表示 从字符串开头,匹配一个数字,后面紧接着0或1个数字,最后是字符串结束

要编写一个正则表达式,以便匹配单词'mail'、'letter'或'correspondence'中的任何一个,但不能匹配包含这些单词的单词,例如'email'、'mailman'、'mailer'和'letterbox',可以从匹配'mail'的正则表达式开始。完全表达的正则表达式是m{1,1}a{1,1}i{1,1}l{1,1},但由于字符表达式会自动使用{1,1}进行量化,因此我们可以简化正则表达式为mail,即一个'm'后面跟一个'a',再跟一个'i',最后跟一个'l'。现在我们可以使用竖线|,它表示,以包含其他两个单词,因此我们匹配这三个单词中的任何一个的正则表达式变为mail|letter|correspondence。匹配'mail'、'letter'或'correspondence'。虽然这个正则表达式会匹配我们想要匹配的三个单词中的一个,但它也会匹配我们不想匹配的单词,例如'email'。为了防止正则表达式匹配不需要的单词,我们必须告诉它从单词边界开始和结束匹配。首先,我们将正则表达式括号化,(mail|letter|correspondence)。括号用来组合表达式,并且它们标识了正则表达式的一部分,我们希望捕获的部分。将表达式括号化可以让我们将其用作更复杂正则表达式的一个组成部分。它还允许我们检查实际上匹配了哪三个单词。为了强制匹配从单词边界开始和结束,我们将在正则表达式周围包含\b 单词边界断言\b(mail|letter|correspondence)\b。现在这个正则表达式意味着:匹配一个单词边界,然后是括号内的正则表达式,然后是单词边界。断言\b匹配正则表达式中的位置,而不是字符。单词边界是非单词字符,例如空格、换行符或字符串的开始或结束。

如果我们想用HTML实体&amp;替换和字符,匹配的正则表达式很简单,即&。但这个正则表达式也会匹配已经转换为HTML实体的和字符。我们只想替换后面没有紧跟amp;的和字符。为此,我们需要负向前瞻断言(?!__)。正则表达式可以写成&(?!amp;),即匹配一个和字符,它后面不是跟了

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

上面讨论的一些示例在代码示例部分实施。

字符集的字符和缩写

元素含义
c除非它是正则表达式的特殊含义的字符,否则字符表示其本身。例如: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对应的Unicode字符(0x0000和0xFFFF之间)。
\0ooo(即\zero ooo匹配八进制数ooo对应的ASCII/Latin1字符(0和0377之间)。
(点)匹配任何字符(包括换行符)。
\d匹配一个数字(QChar::isDigit())。
\D匹配非数字。
\s匹配空格字符(QChar::isSpace())。
\S匹配非空格字符。
\w匹配单词字符(QChar::isLetterOrNumber(),QChar::isMark()或'_')。
\W匹配非单词字符。
\nn 个回溯引用,例如 \1,\2 等。

注意: C++ 编译器会转换字符串中的反斜杠。要在正则表达式中包含一个 \,请输入两个,即 \\。要匹配反斜杠字符本身,请输入四个,即 \\\\

字符集

方括号意味着匹配方括号内的任何字符。上面描述的字符集缩写可以出现在方括号内的字符集中。除字符集缩写和以下两个例外外,字符在方括号中没有特殊含义。

^如果它在第一个字符(即在打开方括号之后立即出现)中出现,则表示否定字符集。 [abc] 匹配 'a' 或 'b' 或 'c',但 [^abc] 匹配除 'a' 或 'b' 或 'c' 以外的任何内容。
-破折号表示字符范围。 [W-Z] 匹配 'W' 或 'X' 或 'Y' 或 'Z'。

使用预定义的字符集缩写比使用平台和语言间的字符范围更便携。例如,[0-9] 匹配西文字符中的数字,但 \d 匹配 任何 字母表中的数字。

注意:在其他正则表达式文档中,字符集组通常称为“字符类”。

量词

默认情况下,表达式通过 {1,1} 自动量词,即它应该恰好出现一次。在以下列表中,E 代表表达式。一个表达式可以是字符,或者字符集的缩写,或者方括号中的字符集,或者括号中的表达式。

E?匹配 E 的零次或一次出现。这个量词的意思是 前面的表达式是可选的,因为它将会匹配表达式是否被找到。 E?E{0,1} 相同。例如, dents? 匹配 'dent' 或 'dents'。
E+匹配 E 的一次或多次出现。 E+E{1,} 相同。例如, 0+ 匹配 '0','00','000' 等。
E*匹配 E 的零次或多次出现。它与 E{0,} 相同。 * 量词通常用于本应使用 + 的错误位置。例如,如果 \s*$ 用于一个表达式以匹配以空格结尾的字符串,它将匹配每个字符串,因为 \s*$ 表示 匹配零个或多个空格后跟字符串结束。匹配至少有一个尾部空格字符的字符串的正确正则表达式是 \s+$
E{n}匹配正好 nEE{n} 与重复 E n 次相同。例如, x{5}xxxxx 相同。它也与 E{n,n} 相同,例如 x{5,5}
E{n,}至少匹配 nE
E{,m}最多匹配 mEE{,m}E{0,m} 相同。
E{n,m}至少匹配 n 次且最多匹配 mE

要将量词应用于不仅仅是前面的字符,请使用括号将字符组合在一起。例如, tag+ 匹配一个 't' 后跟一个 'a' 后跟一个至少的 'g',而 (tag)+ 匹配至少一次出现的 'tag'。

注意:量词通常是“贪婪的”。它们总是尽可能多地匹配文本。例如, 0+ 匹配找到的第一个零及其后面的所有连续零。应用于 '20005' 时,它匹配 '20005'。量词可以通过查看 setMinimal 来设置为非贪婪。

捕获文本

括号可以帮助我们将元素分组,以便我们可以对它们进行数量化和捕获。例如,如果我们有一个表达式 mail|letter|correspondence,它匹配我们已知的字符串,我们可以确定 单词中有一个 匹配,但并不知道是哪一个。使用括号可以让我们“捕获”它们范围内的任何匹配内容,所以如果我们使用 (mail|letter|correspondence) 并将此正则表达式与字符串 "我给你发了电子邮件" 匹配,我们可以使用 cap() 或 capturedTexts() 函数来提取匹配的字符,在这种情况下就是 'mail'。

我们可以在正则表达式中使用捕获的文本。要引用捕获的文本,我们使用 反向引用,它们从1开始编号,与cap() 相同。例如,我们可以使用 \b(\w+)\W+\1\b 在字符串中查找重复的单词,这意味着匹配一个单词边界后跟一个或多个单词字符,然后是一个或多个非单词字符,然后是与第一个括号表达式中相同的文本,之后是另一个单词边界。

如果我们纯粹想用括号分组而不想用捕获,我们可以使用非捕获语法,如 (?:green|blue)。非捕获括号从'(?:'开始,以')'结束。在这个例子中,我们匹配'green'或'blue',但不捕获匹配的内容,所以我们只知道是否匹配了,但不知道实际上是哪种颜色。使用非捕获括号比使用捕获括号更高效,因为正则表达式引擎需要做更少的记录。

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

出于历史原因,应用于捕获括号的量词(例如 *)比其他量词更“贪婪”。例如,a*(a*) 将匹配 "aaa",cap(1) == "aaa"。此行为与其他正则表达式引擎的做法不同(特别是,Perl)。要获得更直观的捕获行为,请将 QRegExp::RegExp2 传递给 QRegExp 构造函数,或调用 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"]

断言

断言在正则表达式中表示它们发生的位置的文本,但它们不匹配任何字符。在下表中 E 代表任何表达式。

^符号表示字符串的开始。如果您想匹配字面量 ^,必须通过写入 \\^ 来转义它。例如,^#include 将只匹配以 '#include' 为开头的字符串。(当开钉符号是字符集的第一个字符时,它有特殊含义,请参阅字符集。)
$符号表示字符串的结束。例如,\d\s*$ 将匹配以数字结尾的字符串,后面可以跟空格。如果您想匹配字面量 $,必须通过写入 \\$ 来转义它。
\b单词边界。例如,正则表达式 \bOK\b 表示匹配位于单词边界之后(例如字符串开头或空白)的字母 'O',然后是紧接着的字母 'K',然后是另一个单词边界之前(例如字符串结尾或空白)。但请注意,断言实际上不匹配任何空白,所以如果我们写入 (\bOK\b) 并有匹配,它将只包含 'OK',即使字符串是 "It's OK now"。
\B非单词边界。此断言在\b为假的情况下为真。例如,如果我们搜索“Left on”中的\Bon\B,就不会匹配(空格和字符串末尾不是非单词边界),但在“tonne”中会匹配。
(?=E)正向先行断言。此断言在正则表达式中的此处匹配时为真。例如,const(?=\s+char)只要其后跟有'char',就会匹配'const',比如在'protoconst char*'中。(与const\s+char相比,它匹配'proto const char *'。)
(?!E)负向先行断言。此断言在正则表达式中的此处不匹配时为真。例如,const(?!\s+char)匹配'const' 除了其后跟有'char'时。

通配符匹配

大多数命令shell,例如bashcmd.exe,支持“文件通配”,即可以使用通配符标识一组文件。使用setPatternSyntax()函数在正则表达式模式和通配符模式之间切换。通配符匹配比完整正则表达式简单得多,并且只有四个功能

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

在通配符模式中,通配符字符不能被转义。在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用户注意事项

Perl支持的大多数字符类缩写均由QRegExp支持,请参阅字符集和缩写

在QRegExp中,除了在字符类内,^始终表示字符串的开始,因此必须始终转义除非它被用于该目的。在Perl中,尖括号的意义会自动根据其出现位置而变化,因此转义它很少是必要的。同样适用的是$,在QRegExp中始终表示字符串的结束。

QRegExp的量词与Perl的贪婪量词相同(但请参阅上面的说明)。不能将非贪婪匹配应用于单个量词,但可以将它应用于模式中的所有量词。例如,要匹配Perl正则表达式ro+?m需要

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

Perl的/i选项等效于setCaseSensitivity(Qt::CaseInsensitive)。

Perl的/g选项可以使用循环来模拟。

在QRegExp中,.匹配任何字符,因此所有QRegExp正则表达式都具有Perl的/s选项等效。QRegExp没有Perl的/m选项等效,但可以通过多种方式模拟,例如通过按行分割输入或在循环中使用搜索新行的正则表达式。

由于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),或正则表达式注释,例如(?#comment)。另一方面,可以采用C++的文本字面量规则来实现相同的功能

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

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

也支持非捕获括号,其语法与(?:pattern)相同。

参见QString::split()和QStringList::join(),它们对应于Perl的split和join函数。

注意:因为C++会转换\'字符,它们必须在代码中写两次,例如\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'。这是一个简单的用于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'或'correspondence'的字符串,但只匹配整个单词,即不是'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

第二个字符串匹配"请写上letter"。单词'letter'也被捕获(因为括号)。我们可以这样查看我们捕获的文本

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

这将捕获第一个捕获括号内的文本(从左到右计算捕获的左括号)。括号从1开始计数,因为cap(0)是整个匹配的正则表达式(在大多数正则表达式引擎中相当于&)。

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's 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()函数来反复匹配字符串中的正则表达式。注意,我们不一定每次移动一个字符,而可以写作pos++,或者可以写pos += rx.matchedLength()以跳过已匹配的字符串。计数等于3,匹配"One Eric another Eirik,和一个Ericsson。有多少个Eirik,Eric?";它不匹配"Ericsson"或"Eiriks",因为它们没有被非单词边界限定。

正则表达式的一个常见用途是将分隔数据行分割成其组成部分字段。

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);
}

在这个示例中,我们的输入行格式为公司名称、网址和国家。遗憾的是,正则表达式相当长并且不够灵活——如果我们添加更多字段,代码将会出错。更简单、更好的解决方案是找到分隔符,在这种情况下是'\t',并获取周围文本。《a href="qstring.html#split" translate="no">QString::split()函数可以接受一个分隔符字符串或正则表达式作为参数,并根据它相应地分割字符串。

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

通配符匹配由于其简单性而可能很方便,但任何通配符正则表达式都可以使用完整正则表达式来定义,例如.*\.html$。注意,我们无法通过通配符匹配同时具有.html.htm文件的扩展名,除非我们使用*.htm*,这将匹配'test.html.bak'。一个完整正则表达式可以给我们所需的精确性,.*\.html?$

QRegExp可以使用setCaseSensitivity()进行不区分大小写的匹配,并且可以使用非贪婪匹配,参见setMinimal。默认情况下,QRegExp使用完整的正则表达式,但可以使用setPatternSyntax()进行更改。可以使用indexIn()向前搜索,或使用lastIndexIn()向后搜索。可以使用capturedTexts()获取捕获的文本,它返回所有捕获字符串的字符串列表,或使用cap()获取特定索引处的捕获字符串。函数pos()接受一个匹配索引,返回字符串中匹配的位置(如果没有匹配则为-1)。

迁移到QRegularExpression

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

其他差异在下文中概述。

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

不同的样式语法

将正则表达式从QRegExp迁移到QRegularExpression可能需要对样式本身进行更改。

在特定场景下,QRegExp过于宽松,接受在QRegularExpression中使用时无效的模式。这些很容易检测到,因为使用这些模式建立的QRegularExpression对象是无效的(参见QRegularExpression::isValid()).

在其他情况下,从QRegExp迁移到QRegularExpression的模式可能会在语义上默默改变。因此,必须审查所使用的模式。最显著的默默不兼容的例子是

  • 对于多于两位的十六进制转义序列(如\xHHHH),需要使用花括号。例如,正则表达式\x2022需要迁移到\x{2022},否则它将匹配一个空格(0x20)后跟字符串"22"。一般来说,非常推荐始终使用带花括号的\x转义,无论指定了多少位数。
  • 需要将{,n}这样的0到n的量化迁移到{0,n}以保留语义。否则,如\d{,3}这样的正则表达式将匹配一个数字后跟确切字符串{,3}"
  • QRegExp默认执行 Aware of the Unicode Match,而QRegularExpression需要一个单独的选项;下面将提供更多细节。
  • 在QRegExp中,c{.}默认匹配所有字符,包括换行符。QRegularExpression默认排除换行符。要包括换行符,请设置QRegularExpression::DotMatchesEverythingOption样式选项。

有关 QRegularExpression 支持的正则表达式语法的概述,请参阅pcrepattern(3) 手册页,该页介绍了 PCRE(Perl 兼容正则表达式的参考实现)支持的语法模式。

从 QRegExp::exactMatch() 构建迁移

QRegExp::exactMatch() 具有两种用途:它将正则表达式与主题字符串精确匹配,并实现部分匹配。

从 QRegExp 的精确匹配迁移

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

QRegExp::exactMatch()QRegularExpressionMatch::hasMatch()
"\\d+"falsetrue
"[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 匹配任何具有 Unicode Nd (十进制数字)属性的字符。

这些字符类默认只匹配 ASCII 字符:例如,\d 只匹配 ASCII 范围内的 0-9 字符。使用 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 不支持懒惰量词,如 *?, +? 等)。相反,QRegularExpression 支持贪婪、懒惰和占有量词。可以使用QRegularExpression::InvertedGreedinessOption 模式选项来模拟 QRegExp::setMinimal() 的效果:如果启用,它将反转量词的贪婪性(贪婪的变为懒惰的,反之亦然)。

光标模式

可以使用 QRegularExpression::AnchorAtOffsetMatchOption 匹配选项来模拟 QRegExp::CaretAtOffset 的行为。其他 QRegExp::CaretMode 模式没有等效项。

另请参阅 QStringQStringListQSortFilterProxyModel

成员类型文档

enum QRegExp::CaretMode

CaretMode 枚举定义了正则表达式中文档的不同含义。可能的值包括

常量描述
QRegExp::CaretAtZero0光标对应于搜索字符串中的索引 0。
QRegExp::CaretAtOffset1光标对应于搜索的起始偏移量。
QRegExp::CaretWontMatch2光标从不匹配。

enum QRegExp::PatternSyntax

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

常量描述
QRegExp::RegExp0这是一种丰富的 Perl 样式模式匹配语法。这是默认设置。
QRegExp::RegExp23类似于 RegExp,但带有 贪婪量词。(自 Qt 4.2 以来引入。)
QRegExp::Wildcard1这提供了一种类似于 shell(命令解释器)用于 "文件通配符" 的简单模式匹配语法。请参阅 QRegExp 通配符匹配
QRegExp::WildcardUnix4这与 Wildcard 相似,但具有 Unix shell 的行为。通配符字符可以使用字符 "\" 来转义。
QRegExp::FixedString2模式是一个固定字符串。这相当于在使用 escape() 转义所有元字符之后在字符串上使用 RegExp 模式。
QRegExp::W3CXmlSchema115模式是 W3C XML Schema 1.1 规范定义的正则表达式。

另请参阅 setPatternSyntax()。

成员函数文档

QRegExp::QRegExp()

构造一个空的正则表达式。

另请参阅 isValid() 和 errorString

[显式] 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

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

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

例如

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;
}

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

字符串列表中元素的顺序如下。第一个元素是整个匹配字符串。接下来的每个元素对应于下一个捕捉左括号。因此,capturedTexts()[1] 是第一个捕捉括号的文本,capturedTexts()[2] 是第二个,依此类推(对应于某些其他正则表达式语言中的 $1, $2 等)。

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

Qt::CaseSensitivity QRegExp::caseSensitivity() const

如果正则表达式是区分大小写的,则返回 Qt::CaseSensitive;否则返回 Qt::CaseInsensitive

另请参阅 setCaseSensitivity(),patternSyntax(),pattern() 和 isMinimal()。

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

返回这个正则表达式在 str 中匹配的次数。

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

QString QRegExp::errorString() const

返回一个文本字符串,解释正则表达式模式无效的原因;如果没有错误发生,则返回 "no error occurred"。

另请参阅 isValid()。

[静态] QString QRegExp::escape(const QString &str)

返回字符串 str,其中每个正则表达式特殊字符都使用反斜杠转义。特殊字符是 $, (,), *, +, ., ?, [, ], ^, {, | 和 }。

示例

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

此函数对于构建正则表达式模式动态非常有用

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()。

例如,如果正则表达式是 blue,则 exactMatch() 只在输入 blue 时返回 true。对于输入 bluebellblutaklightblue,exactMatch() 返回 false,而 matchedLength() 分别返回 4,3 和 0。

尽管是 const,但此函数设置了 matchedLength(),capturedTexts() 和 pos()。

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

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

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

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

尝试从偏移量 offset(默认为0)开始在 str 中查找匹配项。如果 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 ()。

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

返回正则表达式在 list 中第一次精确匹配的索引位置,从索引位置 from 开始向前搜索。如果没有项匹配,则返回 -1。

另请参阅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 QString &str, int offset = -1, QRegExp::CaretMode caretMode = CaretAtZero) const

尝试从位置offsetstr中逆向查找匹配项。如果offset为 -1(默认值),则搜索从最后一个字符开始;如果为 -2,则从倒数第二个字符开始;依此类推。

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

可以使用 caretMode 参数来指示 ^ 是否应匹配索引 0 或 offset

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

注意: 逆向搜索比正向搜索慢得多。

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

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

返回此正则表达式在list中的最后一个完整匹配项的索引位置,从索引位置from逆向搜索。如果from为 -1(默认值),则搜索从最后一个项目开始。如果没有找到匹配项,则返回 -1。

另请参阅QRegExp::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)

对于零长度匹配,pos() 总是返回 -1。例如,如果 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

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

对于包含捕获括号的正则表达式,after中的\1\2,... 将被替换为rx.cap(1), cap(2), ...

另见 indexIn(),lastIndexIn() 和 QRegExp::cap().

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

将此正则表达式中的每个出现,分别替换成stringList中的after。返回字符串列表的引用。

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

设置是否区分大小写匹配为cs

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

另见 caseSensitivity(),setPatternSyntax(),setPatternsetMinimal

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>!"。但是在最小(非贪婪)匹配的情况下,第一个匹配是"We must be <b>bold</b>, very <b>bold</b>!",第二个匹配是"We must be <b>bold</b>, very <b>bold</b>!"。实际上我们可能会使用模式<b>[^<]*</b>来代替,尽管这仍然会失败于嵌套标签。

另见 isMinimal()和setCaseSensitivity

void QRegExp::setPattern(const QString &pattern)

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

另见 patternsetPatternSyntaxsetCaseSensitivity

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

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

syntax设置为QRegExp::Wildcard将启用简单的shell-likeQRegExp通配符匹配。例如,在通配符模式下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==()。

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

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

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

other 移动赋值到此 QRegExp 实例上。

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

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

两个 QRegExp 对象相等当且仅当它们的模式字符串相同,且对大小写敏感、通配符和最小匹配的设置也相同。

相关非成员函数

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

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

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

将正则表达式 regExp 写入流 out

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

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

从流 in 中读取正则表达式到 regExp

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

© 2024 Qt 公司有限公司。此处包含的文档贡献版权归各自所有者。提供的文档是根据自由软件基金会发布的 GNU 自由文档许可协议版本 1.3 的条款许可的。Qt 及相关标志是芬兰 Qt 公司及/或全球各地的商标。所有其他商标均为各自所有者的财产。