Qt C++ :QRegularExpression 正则表达式使用详解

文章目录


QRegularExpression类

Qt5.0引入,用于解析正则表达式的类

基于 PCRE2(Perl Compatible Regular Expressions)

功能强大、性能好、支持 Unicode

是现代 Qt 应用的首选

基本用法示例

1. 匹配字符串是否符合模式

cpp 复制代码
#include <QRegularExpression>
#include <QDebug>

QString email = "user@example.com";
QRegularExpression re(R"(^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)");
QRegularExpressionMatch match = re.match(email);

if (match.hasMatch()) {
    qDebug() << "Valid email!";
}

注意:使用原始字符串字面量 R"(...)" 避免反斜杠转义问题。
R"(...)" 是 C++11 引入的原始字符串字面量(Raw String Literal) 语法,不是 Qt 特有的,而是标准 C++ 的特性。它常被 Qt 开发者用于书写正则表达式、文件路径、SQL 语句等包含大量反斜杠 \ 或引号的字符串,以避免繁琐的转义。

2. 提取捕获组(Capturing Groups)

cpp 复制代码
QString text = "Date: 2026-01-01";
QRegularExpression re(R"(Date: (\d{4})-(\d{2})-(\d{2}))");
QRegularExpressionMatch match = re.match(text);

if (match.hasMatch()) {
    QString year = match.captured(1); // "2026"
    QString month = match.captured(2); // "01"
    QString day = match.captured(3); // "01"
}
  • captured(0) 是整个匹配
  • captured(n) 是第 n 个括号内的内容

3. 全局查找所有匹配项

cpp 复制代码
QString text = "cat dog cat bird";
QRegularExpression re("cat");
QRegularExpressionMatchIterator it = re.globalMatch(text);

while (it.hasNext()) {
    QRegularExpressionMatch match = it.next();
    qDebug() << "Found at position:" << match.capturedStart();
}

4. 替换文本

cpp 复制代码
QString text = "Hello 123 World 456";
QRegularExpression re("\\d+");
QString result = re.replace(text, "NUM"); 
// 结果: "Hello NUM World NUM"

支持使用捕获组进行替换:

cpp 复制代码
QString text = "John Doe";
QRegularExpression re("(\\w+) (\\w+)");
QString result = re.replace(text, "\\2, \\1"); 
// 结果: "Doe, John"

常用选项(Pattern Options)

通过 QRegularExpression::setPatternOptions() 或构造时传入选项:

cpp 复制代码
QRegularExpression re("hello", QRegularExpression::CaseInsensitiveOption);

常用选项:

  • CaseInsensitiveOption:忽略大小写
  • DotMatchesEverythingOption:. 匹配包括换行符
  • MultilineOption^$ 匹配每行开头结尾
  • ExtendedPatternSyntaxOption:允许正则中加注释和空白(类似 Perl/x

性能建议

  • 预编译正则表达式:避免在循环中重复构造 QRegularExpression

  • 使用 isValid() 检查合法性:

    cpp 复制代码
    if (!re.isValid()) {
        qDebug() << "Regex error:" << re.errorString();
    }
  • 对于简单匹配(如固定字符串),优先考虑 QString::contains()startsWith() 等,性能更高


常见应用场景

场景 正则示例
验证邮箱 ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
提取 URL https?://[^\s]+
数字验证 ^-?\d+(\.\d+)?$
去除 HTML 标签 <[^>]*>
分割驼峰命名 ([a-z])([A-Z]) → 替换为 $1 $2

在 UI 输入验证中(如 QLineEdit + QValidator),可结合 QRegularExpressionValidator 使用:

cpp 复制代码
QRegularExpression re("\\d{3}-\\d{2}-\\d{4}"); // 社保号格式
QRegularExpressionValidator *validator = new QRegularExpressionValidator(re, this);
lineEdit->setValidator(validator);

正则表达式

正则表达式(Regular Expression,简称 regex)是一种用于匹配、查找、替换文本的强大工具。其核心在于模式(pattern),而模式由各种符号(元字符、量词、分组、断言等)组成。以下是正则表达式中各组常用符号的详细定义与分类说明,适用于大多数现代正则引擎(包括 Qt 的 QRegularExpression,基于 PCRE2)。

基本字符与字面量

符号 含义
a, 1, @ 普通字符,匹配自身
\n 换行符(在字符串中需注意转义)
\t 制表符

元字符(Metacharacters)

这些字符有特殊含义,若要匹配字面值,需用反斜杠转义:

元字符 含义
. 匹配任意单个字符(默认不包括换行符;可用 s 标志使 . 匹配换行)
^ 匹配字符串开头(或多行模式下每行开头)
$ 匹配字符串结尾(或多行模式下每行结尾)
\ 转义字符,用于取消元字符特殊含义或引入特殊序列

字符类(Character Classes)

符号 含义
[abc] 匹配 a、b 或 c 中任意一个
[^abc] 否定字符类:匹配不是 a、b、c 的任意字符
[a-z] 匹配 a 到 z 的小写字母
[0-9] 匹配数字 0--9
[A-Za-z0-9_] 等价于 \w(见下)

预定义字符类(Shorthand)

表格

符号 含义 等价形式
\d 数字 [0-9]
\D 非数字 [^0-9]
\w 单词字符(字母、数字、下划线) [A-Za-z0-9_](注意:在 Unicode 模式下可能包含其他语言字母)
\W 非单词字符 [^A-Za-z0-9_]
\s 空白字符(空格、制表、换行等) [ \t\r\n\f\v]
\S 非空白字符 [^ \t\r\n\f\v]

Qt 的 QRegularExpression 默认启用 Unicode,因此 \w 可能匹配中文、阿拉伯字母等(取决于上下文)。

量词(Quantifiers)

用于指定前面元素出现的次数。

量词 含义 示例
* 0 次或多次(贪婪) a* → "", "a", "aaa"
+ 1 次或多次(贪婪) a+ → "a", "aaa"(不匹配空)
? 0 次或 1 次(可选) colou?r → "color" 或 "colour"
{n} 恰好 n 次 \d{4} → 匹配 4 位数字
{n,} 至少 n 次 \d{2,} → 2 位或更多数字
{n,m} n 到 m 次 \d{2,4} → 2~4 位数字

贪婪 vs 懒惰(非贪婪)

  • 默认是贪婪:尽可能多匹配
  • 加 ? 变成懒惰:尽可能少匹配
贪婪 懒惰 说明
* *?
+ +?
? ??
{n,m} {n,m}?

示例:

regex 复制代码
<a>.*</a>      // 贪婪:匹配整个 <a>...</a>...<a>...</a>
<a>.*?</a>     // 懒惰:只匹配第一个 <a>...</a>

分组与捕获(Grouping & Capturing)

符号 含义
(expr) 捕获组:将 expr 作为一个单元,并保存匹配内容供后续引用(如 \1, $1
(?:expr) 非捕获组:仅分组,不保存匹配内容(性能更好)
\1, \2... 反向引用:引用第 1、2... 个捕获组的内容
(?P<name>expr) 命名捕获组(PCRE 支持):如 (?P<year>\d{4}),可用 match.captured("year") 获取(Qt 支持)

示例(Qt 中):

cpp 复制代码
QRegularExpression re(R"((\d{4})-(\d{2}))");
auto match = re.match("2026-01");
match.captured(1); // "2026"
match.captured(2); // "01"

命名组示例:

cpp 复制代码
QRegularExpression re(R"((?<year>\d{4})-(?<month>\d{2}))");
auto match = re.match("2026-01");
match.captured("year");  // "2026"
match.captured("month"); // "01"

边界与断言(Assertions)

这些不消耗字符,只判断位置。

符号 含义
\b 单词边界(如字母与非字母之间)
\B 非单词边界
^ 字符串/行开头
$ 字符串/行结尾
(?=expr) 正向先行断言:后面必须是 expr,但不包含 expr
(?!expr) 负向先行断言:后面不能是 expr
(?<=expr) 正向后行断言(PCRE2 支持):前面必须是 expr
(?<!expr) 负向后行断言

示例:

regex 复制代码
\w+(?=;)       // 匹配后面跟着分号的单词,但不包含分号
\d{3}(?!\d)    // 匹配三位数,且后面不是数字(避免匹配 1234 中的 123)

修饰符 / 标志(Flags)

控制正则行为,可在模式中内联或通过 API 设置:

标志 内联写法 作用
i (?i) 忽略大小写
m (?m) 多行模式(^/$ 匹配每行)
s (?s) 单行模式(. 匹配包括换行符)
x (?x) 扩展模式(忽略空白和注释)

示例:

cpp 复制代码
// Qt 中设置标志
QRegularExpression re(R"(\d+)", QRegularExpression::CaseInsensitiveOption);

// 或在模式中内联
QRegularExpression re(R"((?i)hello)"); // 匹配 hello, Hello, HELLO 等

特殊结构

结构 含义
` `
(?>expr) 原子组(禁止回溯,提高性能)
(?#comment) 注释(仅在 x 模式下有效)

总结

类别 符号 用途
字符类 \d, \w, \s 数字、单词、空白
量词 *, +, ?, {n,m} 重复次数
分组 (...), (?:...) 捕获 / 非捕获
边界 \b, ^, $ 位置匹配
断言 (?=...), (?!...) 条件判断
转义 \ 取消特殊含义
` `
  • 使用 R"(...)" 避免 C++ 字符串转义
  • 优先用 QRegularExpression(非 QRegExp)
  • 用 captured(n) 或 captured("name") 提取内容
  • 用 globalMatch() 遍历所有匹配
相关推荐
闻缺陷则喜何志丹4 小时前
【回文 字符串】3677 统计二进制回文数字的数目|2223
c++·算法·字符串·力扣·回文
李余博睿(新疆)4 小时前
c++分治算法
c++
qq_401700414 小时前
QStackedLayout 实现遮罩层
qt
oioihoii4 小时前
Protocol Buffers 编码原理深度解析
c++
消失的旧时光-19434 小时前
函数指针 + 结构体 = C 语言的“对象模型”?——从 C 到 C++ / Java 的本质统一
linux·c语言·开发语言·c++·c
郝学胜-神的一滴4 小时前
Linux系统编程:深入理解读写锁的原理与应用
linux·服务器·开发语言·c++·程序人生
Larry_Yanan4 小时前
Qt多进程(十一)Linux下socket通信
linux·开发语言·c++·qt
weixin_462446234 小时前
Python 使用 PyQt5 + Pandas 实现 Excel(xlsx)批量合并工具(带图形界面)
python·qt·pandas
DYS_房东的猫4 小时前
《 C++ 零基础入门教程》第3章:结构体与类 —— 用面向对象组织代码
开发语言·c++