文章目录
- 1 应用
- 2 简介
- 2.1 组成
- 2.2 特殊字符
- 2.2.1 匹配多个字符串
- 2.2.2 替换字符串
- 2.2.3 统计字符出现次数
- 2.3 Qt中使用
- 3 regexp结构集合
- 3.1 表达式
- 3.2 量词
- 3.3 断言
- 3.4 通配符
- 4 文本捕获
- 5 QRegularExpression
- 5.1 模式字符串
- 5.2 设置模式
1 应用
- 1验证:测试一个子字符串是否是符合一些规范。(例如:是否是一个整数或者不包含任何空格)
- 2 搜索:提供了比简单的子字符串匹配更加强大的匹配模式。(例如,匹配单词mail或者letter,而不匹配email、mailman或者letterbox)
- 3 查找或替换:使用一个不同的字符串替换所有的匹配的子字符串(例如使用Mail替换一个字符串中所有的M字符)
- 4 字符串分割:可以识别在那里进行字符串分割。例如,分割制表符隔离的字符串。
Qt中的QRegExp类实现了使用正则表达式进行模式匹配。QRegExp是以Perl的正则表达式语言为蓝本,它可以完全支持Unocode。QRegExp中的愈发规则可以使用setPatternSyntax函数来更改。
2 简介
2.1 组成
一个正则表达式由表达式(expressions)、量词(quantifiers)和断言(assertions)组成。
表达式:
- 一个简答的表达式就是一个字符。
- 例如:x和5。
- 一组字符可以使用方括号括起来。
- 例如:[ABC]会匹配A、B、C,也可以简写为[A-C]。
量词:
- 必须要匹配表达式出现的次数。
- x{1,1}意味着必须匹配且只能匹配一个字符;
- x{1,5}意味着匹配一列字符x,其中至少包含一个字符x,但是最多包含5个字符x。
例如使用regexp匹配0~99之间的整数,
- 因为一个数最多出现次数为2,因此可以写为
[0-9]{1,2}
但是这样写会匹配出现在字符串中间的整数,如果想匹配的整数是整个字符串,那么需要使用断言"^“和”$"。
断言:
- 当^在regexp中作为第一个字符串时,意味着regexp必须从字符串的开始进行匹配;
- 当$在regexp中作为 最后一个字符串时,意味着regexp必须匹配到字符串的结尾。
例如,匹配0~99,^[0,9]{1,2}$
2.2 特殊字符
使用特殊符号表示一些常见的字符组和量词。
- 例如[0,9]使用\d来代替;
- 对于只出现一次的量词{1,1},可以使用表达式本身代替,例如:x{1,1}等价于x
- 要匹配0~99可以写为
^d{1,2}$
或者^\d\d{0,1}
,{0,1}表示字符是可选的,就是只出现一次或者不出现,它可以使用?来代替,这样就变为^\d\d?$
2.2.1 匹配多个字符串
例如要匹配"mail"和"letter"其中的一个,但是不要匹配那些包含这些单词的量词,比如"email"和“letterbox”。
要匹配“mail“,可以写为m{1,1}a{1,1}i{1,1}l{1,1}
或者是mail
.
使用"|"来包含另外一个单词,所以结果为(mail|letter)
为了强制匹配的开始和结束都在单词的边界上,使要将regexp包含在\b单词边界断言中,即\b(mail|letter)\b
.
\b断言在regexp中匹配一个位置,一个单词的边界是任何的非单词字符,如空格、新行或者一个字符串的开始或者结束。
2.2.2 替换字符串
如果像使用"Mail"替换一个字符串中的字符M,但是字符M的后面是"ail"的话就不再替换,可以使用(?!E)
断言。例如这里regexp应该写成M(?!Mail)
2.2.3 统计字符出现次数
如果想统计"Eric"和“Eirik”在字符串中出现的次数,可以使用\b(Eric|Eriik)\b
或\bEi?ri[ck]\b
2.3 Qt中使用
由于"“是转义字符,因此使用”\d"时,要写成"\d";如果需要""本身,需要写成“\\”.
QRegexp中的indexIn()函数:从指定位置开始向后对字符串进行匹配,默认是从字符串开始匹配。
如果匹配成功是,返回第一个匹配到的位置的索引,
如果没有匹配到则返回-1。
setPattern()函数用来输入一个regexp。
QString的replace函数可以使用给定的regexp和替换字符来进行字符串的替换。
QRegExp rx("^\\d\\d?$"); // 两个字符都必须为数字,第二个字符可以没有
qDebug() << rx.indexIn("a1"); // 结果为-1,不是数字开头
qDebug() << rx.indexIn("5"); // 结果为0
qDebug() << rx.indexIn("5b"); // 结果为-1,第二个字符不是数字
qDebug() << rx.indexIn("12"); // 结果为0
qDebug() << rx.indexIn("123"); // 结果为-1,超过了两个字符
qDebug() << "*******************"; // 输出分割符,为了显示清晰
rx.setPattern("\\b(mail|letter)\\b"); // 匹配mail或者letter单词
qDebug() << rx.indexIn("emailletter"); // 结果为-1,mail不是一个单词
qDebug() << rx.indexIn("my mail"); // 返回3
qDebug() << rx.indexIn("my email letter"); // 返回9
qDebug() << "*******************";
rx.setPattern("M(?!ail)"); // 匹配字符M,其后面不能跟有ail字符
QString str1 = "this is M";
str1.replace(rx, "Mail"); // 使用"Mail"替换匹配到的字符
qDebug() << "str1: " << str1; // 结果为this is Mail
QString str2 = "my M,your Ms,his Mail";
str2.replace(rx,"Mail");
qDebug() << "str2: " << str2; // 结果为my Mail,your Mails,his Mail
qDebug() << "*******************";
QString str3 = "One Eric another Eirik, and an Ericsson. "
"How many Eiriks, Eric?"; // 一个字符串如果一行写不完,换行后两行都需要加双引号
QRegExp rx2("\\bEi?ri[ck]\\b"); // 匹配Eric或者Eirik
int pos = 0;
int count = 0;
while (pos >= 0) {
pos = rx2.indexIn(str3, pos);
if (pos >= 0) {
++pos; // 从匹配的字符的下一个字符开始匹配
++count; // 匹配到的数目加1
}
}
3 regexp结构集合
3.1 表达式
^
在方括号中表示相反的意思,[^abc]
表示匹配任何字符除了abc。
-表示范围,[W-Z]
表示WYZ中的其中一个。
3.2 量词
量词一般都会尽可能多的去匹配,如0+
匹配2005时,会匹配3个零,如果想只匹配一个使用setMinimal(true)设置。
3.3 断言
3.4 通配符
QRegExp使用setPatternSyntax()来在通配符和regexp切换。
4 文本捕获
使用括号对一些元素组合在一起,这样既可以对它们进行量化,也可以捕获它们。
使用cap()和capturedTexts()函数来提取匹配字符。
QRegExp rx3("*.txt");
rx3.setPatternSyntax(QRegExp::Wildcard);
qDebug() << rx3.exactMatch("README.txt"); // 结果为true
qDebug() << rx3.exactMatch("welcome.txt.bak"); // 结果为false
QRegExp rx4("(\\d+)");
QString str4 = "Offsets: 12 14 99 231 7";
QStringList list;
int pos2 = 0;
while ((pos2 = rx4.indexIn(str4, pos2)) != -1) {
list << rx4.cap(1); // 第一个捕获到的文本
pos2 += rx4.matchedLength(); // 上一个匹配的字符串的长度
}
qDebug() << list; // 结果12,14,99,231,7
QRegExp rxlen("(\\d+)(?:\\s*)(cm|inch)");
int pos3 = rxlen.indexIn("Length: 189cm");
if (pos3 > -1) {
QString value = rxlen.cap(1); // 结果为189
QString unit = rxlen.cap(2); // 结果为cm
QString string = rxlen.cap(0); // 结果为189cm
qDebug() << value << unit << string;
}
QRegExp rx5("\\b(\\w+)\\W+\\1\\b");
rx5.setCaseSensitivity(Qt::CaseInsensitive); // 设置不区分大小写
qDebug() << rx5.indexIn("Hello--hello"); // 结果为0
qDebug() << rx5.cap(1); // 结果为Hello
QRegExp rx6("\\b你好\\b"); // 匹配中文
qDebug() << rx6.indexIn("你好"); // 结果为0
qDebug() << rx6.cap(0); // 整个字符串完全匹配,使用cap(0)捕获,结果为“你好”
5 QRegularExpression
Qt5中新类,实现了于Perl兼容的正则表达式,这里的正则表达式由模式字符串和一组模式选项。
5.1 模式字符串
QRegularExpression re("a pattern");//构造函数设置模式串
QRegularExpression re2;
re2.setPattern("a pattern");
5.2 设置模式
设置模式
re.setPatternOptions(QRegularExpression::MultilineOption);
QRegularExpression::PatternOptions option = re.patternOptions();
模式选项
示例:
QRegularExpression re("^(\\d\\d)/(\\d\\d)/(\\d\\d\\d\\d)$");
QRegularExpressionMatch match = re.match("08/12/1985");
if (match.hasMatch()) {
QString matched = match.captured(0);
QString day = match.captured(1);
QString month = match.captured(2);
QString year = match.captured(3);
qDebug() << "matched: " << matched << endl
<< "day: " << day << endl
<< "month: " << month << endl
<< "year: " << year;
}
QString pattern("^(Jan|Feb|Mar|Apr|May) \\d\\d?, \\d\\d\\d\\d$");
QRegularExpression re1(pattern);
QString input("Jan 21,");
QRegularExpressionMatch match1 = re1.match(input, 0,
QRegularExpression::PartialPreferCompleteMatch);
bool hasMatch = match1.hasMatch();
bool hasPartialMatch = match1.hasPartialMatch();
qDebug() << "hasMatch: " << hasMatch << "hasParticalMatch: " << hasPartialMatch;
}