文章目录
- QRegularExpression类
- 正则表达式
-
- 基本字符与字面量
- 元字符(Metacharacters)
- [字符类(Character Classes)](#字符类(Character Classes))
- 量词(Quantifiers)
- [分组与捕获(Grouping & Capturing)](#分组与捕获(Grouping & Capturing))
- 边界与断言(Assertions)
- [修饰符 / 标志(Flags)](#修饰符 / 标志(Flags))
- 特殊结构
- 总结
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()检查合法性:cppif (!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() 遍历所有匹配