给出一篇文档,要求把里面的“性爱”都替换成“革命”,“性”都替换成“道德”。删除里面所有的“A片”。在所有的“苍井空来了”前面加上“(表相信)”,后面加上“(这是谣言)”。
要求:考虑周密,设想各种会出现的奇怪情况。因为---我们是国家安全局!宁可错杀一万,不能漏过一个。
首先考虑到肯定要涉及到各种宽字符的过滤故肯定要使用unicode来处理,我们的函数接口不妨设为
static void filter_unicode(std::wstring& ws_text);
然后题目中的三个需求其实都可以概括成将子串A替换为B的操作,故如果没有特殊要求直接三句boost::replace_all即可搞定。
现在来考虑最后的要求中提到的“奇怪情况”,那就需要我们“设身处地”地来思考啦。我们平时想输入敏感字时会用到什么方法呢,无外乎会插入空格或者各种异常标点符号之类,这里会想到用正则表达式岂不正好?符合我们需求的相应函数为std::regex_replace,boost的regex库也有对应函数,这里就用c++ 0x原生的了。
我们的需求是从关键字首字符开始匹配,中间如果只间隔标点符号,且符号结束后的第一个字符与关键字尾字符相匹配,则匹配成功,将此串替换为预设的目标串。要注意到的是c++ 0x和boost中的regex库并不支持unicode库定义,比如\p{L} 之类的定义,不然我们可以简单的使用\p{Punct}来完成这个需求了。详细的符号定义可以参考http://en.wikipedia.org/wiki/Regular_expression,我们这里使用到的是\W,可以排除所有字母(包含中文等)和下划线,于是正则表达式可以写成
性\W*爱
再将下划线补充上即可完成需求
性[\W|_]*爱
最终完成的代码如下:
#include <regex>
#include <locale>
#include <string>
#include <iostream>
static wchar_t* rules[][2] =
{
{L"性(\\W|_)*爱", L"革命"},
{L"性", L"道德"},
{L"A(\\W|_)*片", L""},
{L"苍(\\W|_)*井(\\W|_)*空(\\W|_)*来(\\W|_)*了", L"(表相信)苍井空来了(这是谣言)"},
};
static const int RULE_COUNT = sizeof(rules) / sizeof(rules[0]);
static void filter_unicode(std::wstring& ws_text)
{
for (int i = 0; i < RULE_COUNT; ++i)
ws_text = std::regex_replace(ws_text, std::wregex(rules[i][0]), std::wstring(rules[i][1]));
}
static void test1()
{
std::locale::global(std::locale("chs"));
std::wstring ws_text = L"性不爱性a爱性 \t\r\n`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?·!@#¥%……()——【】{}、,。《》?爱性6A片333苍井空来了555";
std::wcout << "before:" << ws_text << std::endl;
filter_unicode(ws_text);
std::wcout << std::endl << L"---------------------------" << std::endl;
std::wcout << "after:" << ws_text << std::endl;
}
运行结果如下:
来源:oschina
链接:https://my.oschina.net/u/853572/blog/99978