標籤:c++11 horspool algorithm
摘要:
本文給出一個horspool演算法的實現,展示一個使用樣本,並向介紹一個非常好用的UTF8字元轉碼項目,給出一個簡單的測試報告等。
演算法實現:
#include <iostream>#include <unordered_map>//#include <codecvt>#include <fstream>#include <iterator>#include <sstream>#include <bitset>#include "utf8.h"using namespace std;template <typename Key,typename Value>class ShiftTable{ public: ShiftTable(const std::u32string& pattern){ index_=pattern.size(); auto end=pattern.rbegin(); auto head=pattern.rend(); auto cur=end+1; while(cur!=head){ shiftTable_.emplace(make_pair(*cur,cur-end)); ++cur; } } Value operator [](const Key& key){ auto cur=shiftTable_.find(key); if(cur!=shiftTable_.end()) return cur->second; else return index_; } private: unordered_map<Key,Value> shiftTable_; size_t index_;};int HorspoolMatching(const std::u32string & pattern,const std::u32string & text){ if(pattern.empty()||text.empty())return -1; ShiftTable<char32_t,size_t> table(pattern); auto m=pattern.size(); auto n=text.size(); auto i=m-1; while(i<=n-1){ int k=0; while(k<=m-1&&pattern[m-1-k]==text[i-k]) k++; if(k==m) return i-m+1; else i+=table[text[i]]; } return -1;}
在這裡不對horspool 演算法進行闡述,僅分享一個實現而已。
實現中使用std::u32string, 並且我們要求字元採用unicode32,以支援任意國建字元竄的搜尋。
在這裡我強烈推薦大家關注一個輕量開源的utf8轉碼實現,這個是項目首頁utf8
一個使用例子,尋找並替換:
int main(){ //一種比較高效,純C++方式把檔案讀入字串 ifstream filestream("/home/ron/input.in");//該檔案需要以utf8格式儲存(作業系統無要求) stringstream ss; ss<<filestream.rdbuf(); string text(ss.str()); string pattern="你是";//此處"你是"是utf8儲存的,因為源碼在ubuntu下以utf8儲存 std::u32string text32; std::u32string pattern32; utf8::utf8to32(text.begin(), text.end() , back_inserter(text32)); utf8::utf8to32(pattern.begin(), pattern.end() , back_inserter(pattern32)); string repWord="我";//此處"我"是utf8儲存的,因為源碼在ubuntu下以utf8儲存 std::u32string repWord32; utf8::utf8to32(repWord.begin(), repWord.end() , back_inserter(repWord32)); //尋找檔案中的"你是" auto index=HorspoolMatching(pattern32,text32); if( index!=-1 ) { cout<<"found it,at index "<<index<<endl; text32.replace(index,1,repWord32); //替換檔案中,第一"你是"為"我是" ofstream ofilestream("/home/ron/input.in"); ostream_iterator<char> out(ofilestream); utf8::utf32to8(text32.begin(),text32.end(),out); } else { cout<<"not found"<<endl; } return 0;}
上述代碼,是一個使用樣本,它可以跨平台(作業系統支不支援utf8無所謂,我們程式支援utf8/16/32 任意轉碼),所以只要求輸入檔案和模式字串是採用utf8編碼即可。我們知道utf8是網路傳輸採用的標準,並且大多數系統均支援utf8。
我們可以做支援任何編碼的尋找,那樣問題就複雜化了,誰願意無窮盡的陷入到字元編碼中,相信只有這個領域的專家吧。
codecvt:
#include <codecvt>
這個標頭檔是啥?C++11引入的關於字元竄轉碼的實現,可惜gcc到現在還沒有實現,哎,怎麼會?。vc2010以後的版本應該是支援的。有興趣的同學可以自行瞭解。因為我編譯環境是ubuntu gcc所以無法使用codecvt,還有其他的一些字元編碼庫可以用,類似ICU等等,但他們太大了,用起來也麻煩。終於找到utf8輕量級項目,copy源碼即用,它在ubuntu下表現非常好。當然在window下也一樣。缺點無非就是僅支援utf而已。
測試:
我使用一些文本對這個實現和標準庫實現進行對比,時間效能效率相差無幾(標準庫略好一點點)。有一個gcc issue,希望採用Boyer-Moore演算法實現find。所以我猜測gcc對find實現很可能採用的就是horspool演算法,又快又簡單,只是最壞複雜度無法保證。
KMP:
怎麼不見KMP,KMP太複雜了。除非你對演算法有所癖愛,否則沒有任何一個程式員會選擇效率相同,但實現更複雜的演算法。但KMP演算法的思想確實對後續其他演算法產生了影響。
限於本人水平,歡迎大家批評指正。轉載請表明出處,謝謝。
Horspool 演算法C++11實現(支援中英文混合搜尋)