文章目录

  • ​​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 表达式

正则表达式(regular expression)————以Qt为例_特殊字符

正则表达式(regular expression)————以Qt为例_正则表达式_02

​^​​在方括号中表示相反的意思,​​[^abc]​​表示匹配任何字符除了abc。

-表示范围,​​[W-Z]​​表示WYZ中的其中一个。

3.2 量词

正则表达式(regular expression)————以Qt为例_字符串_03

量词一般都会尽可能多的去匹配,如​​0+​​匹配2005时,会匹配3个零,如果想只匹配一个使用setMinimal(true)设置。

3.3 断言

正则表达式(regular expression)————以Qt为例_正则表达式_04

3.4 通配符

正则表达式(regular expression)————以Qt为例_特殊字符_05

QRegExp使用setPatternSyntax()来在通配符和regexp切换。

正则表达式(regular expression)————以Qt为例_正则表达式_06

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

模式选项

正则表达式(regular expression)————以Qt为例_正则表达式_07

正则表达式(regular expression)————以Qt为例_正则表达式_08

示例:

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