ACM C++ 正则表达式使用简明指南

前言

前排提示!!!
这里的正则表达式只用来竞赛!!!!
只谈论正则函数的使用方法,不涉及正则表达式的基础使用方法。

尽管 C++ 的 正则表达式一直为人所诟病,一般人都会推荐你去使用boost的正则,但是ACM竞赛里显然是不能使用boost库的……
据说 C 的正则比 boost 的正则都要快,然而我不会……自然得觉得 C++ 会好用点吧。关于 C 的以后学。

正则表达式类 regex , 头文件即 regex。

三个核心函数

C++ 的正则库有三个常用函数,也是核心函数,分别是regex_match,regex_replace,regex_search
具体见下。我在这里只介绍在ACM里常用的一两个用法,具体了解还请点开各自的官方文档链接,上面有实例代码,非常好懂。

regex_match

regex_match 用来将正则表达式与整个字符串进行匹配,返回一个布尔值,如果匹配成功,返回true,反之,返回false。当然有很多附加功能,用一个match_result 记录匹配,或者各种选项标号什么还是得看上面的链接。

一个常用的方法就是直接regex_match( des , reg )
其中 des 表示待匹配字符串,reg为正则表达式,必须是 regex类。

regex_replace

regex_replace 是用来将所有正则表示匹配到的所有子串,替换成自定义子串。

一个常用的方法是 regex_replace( des,reg,rep )
其中 des 表示待匹配字符串,reg为正则表达式,必须是 regex 类,rep 为你想要替换成的字符串。

regex_search 与 regex_match 类似但略有不同,regex_match 是对字符串进行全词匹配,而regex_search是对这个词进行局部查找。

这个函数,官方文档上貌似只给了一个实例。
这个实例也是我们常用的方法 regex_search( des,mac,reg )
其中,des为待匹配字符串,mac为结果集合,这个结果集合有点讲究,如果字符串是 string 类,那么我们与之对应必须是 smatch 类,如果是 字符数组,则为 cmatch 类。这个可以在 regex_match的实例代码中看到。reg则是我们的正则表达式,必须是regex类。

两个例题

HDU 1039 Easier Done Than Said?

题意:

让你判断一个字符串是否可被接受。接受条件有:

  1. 必须存在一个元音字符
  2. 不能存在连续三个都是元音字符或者三个都是非元音字符
  3. 不能出现除了 ee 或者是 oo 以外的连续字符子串

思路:
建立三个正则表达式,对其全局匹配与判断:

  1. .*[aeiou]+.*
  2. .*([aeiou]{3}|[^aeiou]{3}).*
  3. .*([^eo])\\1.*

AC Code

#include <bits/stdc++.h>

using namespace std;

string des;

int main()
{
    regex reg1(".*([aeiou]{3}|[^aeiou]{3}).*");
    regex reg2(".*[aeiou]+.*");
    regex reg3(".*([^eo])\\1.*");
    while (cin >> des) {
        if (des == "end")
            break;
        if (!regex_match(des, reg1) && regex_match(des, reg2) && !regex_match(des, reg3))
            cout << "<" + des << "> is acceptable." << endl;
        else
            cout << "<" + des << "> is not acceptable." << endl;
    }
    return 0;
}

HDU 6170 Two strings

题意:
给你两个字符串,问你字符匹配。
其中第二个字符串可以转化,.可以转化为单个任意字符,* 必须和前面一个字符相组合,表示前面一个字符可以出现任意次。
.*只能表示任意相同字符的字符串,不能表示任意字符串。

思路:
北邮出的弱数据合集之一。淦。其实这道题用正则写起来不是很困难,但是给我栈溢出了,少考虑一种情况就能AC。
当然再少考虑一种情况还能AC,笑尿。
我想的正解但是栈溢出的是 (.?)\\k* 其中k是需要累加的。
但是 (.)\\k* 就过了,这是不符合题意的 比如 aabbaa.*bb
还有的更荒唐是 (.)\\1* 随便那一对 比如 aabbccddaa.*cc.*就不对了。

有一种写法是对的,就是吧 .*换成(a*|b*|c*|d*)……,个人认为这是对的,但却是无法容忍的!!!

但还是拿上AC代码吧。

#include <bits/stdc++.h>
using namespace std;
char tmp[20];
int main()
{
    int T;
    cin >> T;
    while (T--) {
        string pattern, buf, des;
        cin >> des >> buf;
        int len = buf.length();
        for (int i = 0, k = 0; i < len; i++)
            if (buf[i] == '.' && buf[i + 1] == '*') {
                sprintf(tmp, "(.)\\%d*",++k);
                pattern += tmp;
                i++;
            } else
                pattern += buf[i];
        regex reg(pattern);
        bool judge = regex_match(des, reg);
        puts(judge ? "yes" : "no");
    }
    return 0;
}