手册里使用的词汇是 regexp
优点:
方便地完成字符串的一些处理操作,例如验证、查找、替换和分割等。
类名称为QRegExp类,是基于Perl的正则表达式语言,支持Unicode。
帮助文档中指出:All functions in this class are reentrant.
ps:
reentrant指同一线程多次进出;可以被中断;包含thread-safe;较thread-safe更严格;
thread-safe指多个线程可以同时调用。
正则表达式有表达式、量词和断言组成。
(1)最简单的表达式是一个字符。
x或5.表达式也可以是用方括号括起来的一组字符。 [ABCD]将匹配一个A或一个B或一个C或一个D.我们可以写出与[A-D]相同的表达式,并且匹配英文字母中任何大写字母的表达式都写为[A-Z]。
量词指定必须匹配的表达式的出现次数。 x {1,1}表示只匹配一个x。 x {1,5}表示匹配包含至少一个x但不超过五个的x个字符序列。
请注意,通常regexps不能用于检查平衡括号或标签。 例如,如果< b >标记不是嵌套的,但是如果< b >标记嵌套,则可以编写正则表达式来匹配打开的html < b >及其关闭,相同的正则表达式将匹配 打开< b >标签错误关闭。 对于< b >粗体< b >粗体 的片段,第一个< b >会与第一个匹配,这是不正确的。 但是,可以编写一个正确匹配嵌套括号或标记的正则表达式,但是只有嵌套层次的数量是固定的和已知的。 如果嵌套层数不是固定的,就不可能编写一个不会失败的正则表达式。
假设我们想要一个正则表达式来匹配0到99之间的整数。至少需要一个数字,所以我们从表达式[0-9] {1,1}开始,这个表达式只需要匹配一个数字。 此正则表达式匹配整数,范围为0到9。要匹配达到99的整数,将最大出现次数增加到2,因此正则表达式变为[0-9] {1,2}。 这个正则表达式满足了匹配0到99之间整数的原始要求,但它也会匹配出现在字符串中间的整数。 如果我们希望匹配的整数是整个字符串,我们必须使用锚点断言^(caret)和$$(dollar)(这里只有一个美元的符号,但是只打一个会变成markdown的特殊格式,markdown奇葩的编辑方式,真搞不懂CSDN为啥用这东西。。。)。 当 ^是正则表达式中的第一个字符时,意味着正则表达式必须匹配从字符串的开头。 当$是正则表达式的最后一个字符时,意味着正则表达式必须匹配到字符串的末尾。 正则表达式变成^ [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”从匹配“邮件”的正则表达式开始。充分表达,正则表达式是m {1,1} a {1,1} i {1,1} l {1,1},但是由于一个字符表达式被{1,1}自动量化,我们可以简化正则表达式的邮件,即一个“m”后面跟着一个“a”,其次是一个“i”后面跟着一个“l”。现在我们可以使用竖线|来表示或者包含另外两个单词,所以我们用来匹配这三个单词中的任何一个的正则表达式就是对应的。匹配“邮件”或“字母”或“通信”。虽然这个正则表达式匹配我们想要匹配的三个单词中的一个,但它也会匹配我们不想匹配的单词,例如“email”。为了防止正则表达式匹配不需要的单词,我们必须告诉它开始和结束在单词边界的匹配。首先,我们用括号括起我们的正则表达式,(邮件|信函)。小括号将表达式组合在一起,并识别我们希望捕获的正则表达式的一部分。将括号括起来使我们可以将它用作更复杂的正则表达式中的一个组件。它也使我们能够检查三个词中的哪一个实际上是匹配的。为了强制匹配以单词边界开始和结束,我们用\ b单词边界断言:\ b(mail | letter | correspondence)\ b将正则表达式括起来。现在正则表达式的意思是:匹配一个单词的边界,然后是括号中的正则表达式,然后是单词边界。 \ b声明匹配正则表达式中的一个位置,而不是一个字符。单词边界是任何非单词字符,例如空格,换行符或字符串的开始或结尾。
如果我们想用HTML实体&amp;来替换&符号,那么匹配的正则表达式就是&。 但是这个正则表达式也会匹配已经被转换成HTML实体的&符号。 我们只想替换那些还没有跟在后面的&符号。 为此,我们需要负向前瞻断言(?!__)。 然后可以将正则表达式写为&(?!amp;),即匹配不是跟在后面的&号。
如果我们要计算一个字符串中所有“Eric”和“Eirik”的出现次数,两个有效的解决方案是\ b(Eric | Eirik)\ b和\ bEi?ri [ck] \ b。 字边界断言’\ b’是必需的,以避免匹配包含任何名称的单词,例如,“Ericsson”。 请注意,第二个正则表达式匹配比我们想要的更多的拼写:“Eric”,“Erik”,“Eiric”和“Eirik”。
从帮助文档中摘的例子
1、
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)
2、
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)
The second string matches ‘This_is-OK’. We’ve used the character set abbreviation(缩写) ‘\S’ (non-whitespace(没有空格)) and the anchors(锚?) to match strings which contain(包括) no whitespace.
3、
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
We can see what text we’ve captured like this:
QString captured = rx.cap(1); // captured == "letter"
/* 下面有翻译 */This will capture the text from the first set of capturing parentheses (counting capturing left parentheses from left to right). The parentheses are counted from 1 since cap(0) is the whole matched regexp (equivalent to ‘&’ in most regexp engines).
这将捕获第一组捕获括号中的文本(从左到右计算捕获左括号)。 括号从1开始计数,因为cap(0)是整个匹配的正则表达式(相当于大多数正则表达式引擎中的’&’)。
4、
QRegExp rx("&(?!amp;)"); // match ampersands but not &
QString line1 = "This & that";
line1.replace(rx, "&");
// line1 == "This & that"
QString line2 = "His & hers & theirs";
line2.replace(rx, "&");
// line2 == "His & hers & theirs"
在这里,我们已经将QRegExp传递给了QString的replace()函数,用新的文本替换了匹配的文本。
5、
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, and an Ericsson. How many Eiriks, Eric?; 它不符合“Ericsson”或“Eiriks”,因为它们不受非字界(non-word boundaries)限制。
正则表达式的一个常见用法是将分隔数据的行分割成它们的组件字段。
6、
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”,并采取周围的文本。 QString :: split()函数可以将分隔符字符串或regexp作为参数,并相应地拆分字符串。
QStringList field = str.split("\t");
这里的字段[0]是公司,字段[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
Wildcard matching can be convenient because of its simplicity, but any wildcard regexp can be defined using full regexps, e.g. .*.html$.
Notice that we can’t match both .html and .htm files with a wildcard unless we use * .htm* which will also match ‘test.html.bak’. A full regexp gives us the precision(精度) we need, .*\ .html?$.
QRegExp可以使用setCaseSensitivity()不区分大小写,并且可以使用非贪婪匹配,请参阅setMinimal()。 默认情况下,QRegExp使用完整的正则表达式,但是这可以通过setPatternSyntax()来改变。 可以使用indexIn()向前搜索,也可以使用lastIndexIn()向后搜索。 可以使用capturedTexts()来获取捕获的文本,该文本返回所有捕获的字符串的字符串列表,或者使用cap()返回给定索引的捕获字符串。 pos()函数接受匹配索引并返回匹配字符串中的位置(如果不匹配则返回-1)。