Horspool 算法C++11实现(支持中英文混合搜索)

摘要:

本文给出一个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算法的思想确实对后续其他算法产生了影响。

限于本人水平,欢迎大家批评指正。转载请表明出处,谢谢。

时间: 2024-10-09 16:15:10

Horspool 算法C++11实现(支持中英文混合搜索)的相关文章

调用 Windows 7 中英文混合朗读

1.windows7内置语音识别 2.文本到语音转换增加了 Microsoft Lili - Chinese(China) ,支持中英文混合朗读 3.女声.部分词组基本发音准确 以上让我有做个小程序的冲动:如下: 1.引入SpeechLib.dll 2.创建form 3.编写代码 public partial class FormMain : Form    {        public FormMain()        {            InitializeComponent();

php截取等长UFT8中英文混合字串

由于需要,想实现“php截取等长UFT8中英文混合字串”,可是网上找了很多代码不是有乱码就是不能实现等长(以一个中文长度为单位,两个英文字母算一个长度,如‘等长’长度为2,‘UTF8’长度也是2). 由于utf8编码时,中文为三个字节,英文为一个字节,用substr就会出现乱码,用mb_substr会出现上面的不等长问题,但不会有乱码: 我以字节为单位进行操作,简单实现了一个小程序. 只能在utf8编码是使用. Php代码   /*utf8编码时截取等长中英文字串*/ //英文标点[.,\"\\

VS2010编译器工具cl对c++11标准支持情况测试

本文探讨了VS2010编译工具cl对C++11标准的支持情况,提供了利用C++11新特性的两段代码来进行测试,并同g++ 4.9.3编译器的编译情况相对比.总的说来:VS2010的编译器工具cl部分支持了C++11标准,而g++ 4.9.3则全部支持C++11标准.虽然现在已出现了C++14等新的标准,但熟悉了C++11标准的支持情况有利于我们正确选用符合自己需要的编译工具. 1. 问题产生 一个月前由于编写算法的而使用C++语言,看了一些英文版的算法设计和分析书.一个偶然的机会发现了C++11

Horspool算法-字符串匹配

不得不说ACM哪怕是没有结果,对于算法能力的训练是毋庸置疑的-- 因为老师划了重点,所以讲一下horspool的字符串匹配算法的原理吧. 先声明几个概念,被找的字符串称为匹配串,要找的字符串被称为模式串,当前和模式串相匹配的匹配串的子串被称为匹配子串(废话 在朴素算法中,我们要找一个匹配串是否存在模式串,例如HuangZhi is a genius的匹配串串和ChengJinSen的模式串,那么我们一开始用的方法是用: HuangZhi is(11 character) 去匹配: ChengJi

如何解决Win10启动和登陆界面语言中英文混合显示?

如何解决Win10启动和登陆界面语言中英文混合显示? ?Lander Zhang 专注外企按需IT基础架构运维服务,IT Helpdesk 实战培训践行者http://blog.51cto.com/lander 2018/11/13 7:30 问题描述 某用户使用的Windows 10已经设置了系统语言为英文,但在使用电脑时发现启动和登陆界面语言是中文,登陆进入之后显示的全是英文. 故障分析 Windows 10的系统显示语言实际上可以与启动和登陆界面语言设置不同显示语言的,一般情况在区域与语言

中英文混合字符串截取java

//截取字符串长度(中文2个字节,半个中文显示一个) public String subTextString(String str,int len){ if(str.length()<len/2)return str; int count = 0; StringBuffer sb = new StringBuffer(); String[] ss = str.split(""); for(int i=1;i<ss.length;i++){ count+=ss[i].getB

在YouCompleteMe+Syntastic中添加和取消对C++11的支持

添加对c++11的支持: /.vimrc中添加: let g:syntastic_cpp_compiler = 'g++'  "change the compiler to g++ to support c++11. let g:syntastic_cpp_compiler_options = '-std=c++11 -stdlib=libc++' "set the options of g++ to suport c++11..ycm_extra_conf.py中: 将flags数组

ASP如何计算中英文混合字符串长度和截取字符串

用ASP做网站的时候经常会碰到要截取字符串的情况.ASP中的Len函数不管是中文字符,还是英文字符,统统按一个单位来计算,由于一个中文字符的宽度是一个英文字符宽度的两倍,在中英文混合的情况下字符串实际占用的宽度就不好计算了,如果按照Len函数计算的长度来截取字符串截出来的效果也会长短不一,下面是按照一个汉字相当于两个英文字符来计算字符串长度和截取字符串的代码 计算中英文混合字符串的长度: [vb] view plaincopyprint? function getStringLen(str) o

阿里云数据库产品HybridDB简介——OLAP数据库,支持行列混合存储,为用户提供基于开源 OLTP、OLAP、BigData 生态的一站式解决方案

12 月 9 日,阿里云宣布数据库产品 HybridDB 正式商业化. HybridDB(ApsaraDB HybridDB)是一款在线 MPP 大规模并行处理数据仓库的服务.它基于 Pivotal 公司的开源数据库项目 Greenplum Database 开发,并由阿里云数据库团队在云计算架构下深度扩展. 该服务支持了 OSS 存储.JSON 数据类型.HyperLogLog 预估分析等功能特性.通过符合 SQL2008 标准查询语法及 OLAP 分析聚合函数,提供灵活的混合分析能力.提供在