給出一篇文檔,要求把裏面的“性愛”都替換成“革命”,“性”都替換成“道德”。刪除裏面所有的“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;
- }
運行結果如下: