关于字符串匹配算法有很多,之前我有讲过一篇 KMP 匹配算法:图解字符串匹配 KMP 算法,不懂 kmp 的建议看下,写的还不错,这个算法虽然很牛逼,但在实际中用的并不是特别多。至于选择哪一种字符串匹配算法,在不同的场景有不同的选择。

在我们平时文档里的字符查找里



采用的就是 Boyer-Moore 匹配算法了,简称BM算法。这个算法也是有一定的难度,不过今天,我选用一个例子,带大家读懂这个字符串匹配 BM 算法,看完这篇文章,保证你能够掌握这个算法的思想。

首先我先给出一个字符串和一个模式串

接下来我们要在字符串中查找有没有和模式串匹配的字串,步骤如下:

坏字符

1、



和其他的匹配算法不同,BM 匹配算法,是从模式串的尾部开始匹配的,所以我们把字符串和模式串的尾部对齐。

显然,从图中我们可以发现,s 和 e 并不匹配。这时我们把“s” 称之为坏字符,即代表不匹配的字符。而且我们可以发现,s 和模式串中的任意一个字符都不匹配,所以这时,我们可以直接把模式串移动到 s 的后面。

2、

从图中可以看出,此时 p 和 e 不匹配,所以 p 是一个坏字符,不过,我们可以发现 “p” 包含在模式串中

所以,我们不能像第一步那样,把模式串直接全部移到 p 的后面去,而是移动两位,让两个 p 对齐。

4、

那么问题来了,当我们碰到碰到坏字符的时候,该移动几位呢?

下面我和大家讲一下这个问题,首先我们要算出模式串中两个字符的下标。这两个字符分别是

(1)模式串中与坏字符对应的那个字符的下标,在我们上面那个例子中,就是 e。



显然,这个 e 的下标是 6(从0开始算起)。我们用变量 t1 来代表这个字符的下标吧。

(2)坏字符在模式串中的下标,在我们上面那个例子中,坏字符在模式串中的下标为 4,我们用变量 t2 来代表这个下标,如图

找出这两个字符的下标之后,我们就可以计算移动的位数了

移动的位数 = t1 - t2。

例如上面的例子步骤 2 中 t1 = 6, t2 = 4,所以移动了 t1 - t2 = 2 位。

(1)这个时候可能有人会问了,那如果模式串中有多个 p 呢?

答是如果有多个,我们只计算最右边的那个(当然是移动的位数越少越安全了)

(2)可能又有人会问,那如果模式串中并不存在坏字符呢?例如步骤1

答是如果不存在的话,我们把 t2 赋值为 -1,即 t2 = -1。所以我们步骤 1 中移动了 t1 - t2 = 6 - (-1) = 7 位。

好了,现在我们已经解决了遇到坏字符之后,应该移动多少位的问题了。

好后缀

我们继续匹配

5、



匹配,所以继续匹配前面的字符

6、



匹配,继续匹配前面的字符

7、



匹配,继续匹配前面的字符

8、



匹配,继续匹配前面的字符

9、



遇到坏字符 i,按照我们前面的规则,可以计算出 t1 = 2(就是a的下标)。t2 = -1(因为模式串不存在坏字符)。所以移动的位数是 t1 - t2 = 3。

但是,我想问一下,这是最好的移动方式吗?有没有更好的移动方法呢?接下来我就和大家介绍一种更好的方法,这种方法就是根据好后缀来移动位数。首先我们先介绍下啥的好后缀

在上面的例子中,我们发现 "mple" 是能够成功匹配的



我们把这些能够成功匹配的子串,称之为好后缀,所以呢,e,le,elp,mple 都是好后缀

因为 e, le, elp在之前的步骤中,也是能够成功匹配。不过 mple 是最长的好后缀。

接下来我们要在模式串的前面寻找与好后缀匹配的子串,这句话的意思就是说,我们要在模式串中寻找这样一个子串s:s 与好后缀匹配,并且s中的字符不能与好后缀有重叠。

我举个例子吧,例如有模式串 abcddab,然后好后缀分别是 b, ab, dab。那么与好后缀匹配的字串有 b,ab。(因为abcddab前面中的b可以与好后缀 b 匹配,前面的 ab 与好后缀 ab 匹配)。不过,没有与好后缀 dab 匹配的子串。

那么问题来了,如果我们找到了多个这样的子串的话,我们要选择哪一个呢?例如上面我们找到了两个,分别是 a,ab。

这个时候,我们选择与比较长的那个好后缀匹配的子串,例如,上面的例子中,我们会选择 ab,我们把这个被选中的子串(ab)称之为好前缀吧(我是为了后面方便描述,才给它这个一个称呼)。

找出了好后缀好前缀之后 ,我们就可以知道要移动几位了,公式如下:

移动的位数 = 好后缀的下标 - 好前缀的下标。

当然,好后缀有多个,我们是选择和好前缀匹配的那一个。那么好后缀的下标怎么算呢?,计算方法是按照好后缀的最后一个字符的下标为准,例如模式串 abcddab 中好后缀 ab 的下标为 6(下标从 0 开始算起)。好前缀下标的方法也是一样,以最后一个字符的下标位准,例如模式串 abcddab 中,好前缀 ab 的下标为 1。

这里可能有人会问,那如果不存在这样的好前缀呢?如果不存在的话,就用 -1 充当好前缀的下标。

知道了移动位数之后,我们继续来匹配我们上面的例子

10、



好后缀是 e, le, ple, mple,但是模式串中只有一个子串能够与好后缀 e 匹配,所以好前缀为 e。

显然,这个时候好前缀 e 的下标为 0,好后缀 e 的下标为 6,所以移动的位数为 6。如果按照我们最开始坏字符的移动规则的话,只能移动 3 位,而用好后缀可以移动 6 位。

选择坏字符的规则还是好后缀?

11、

可能有人会问,两个规则我们应该要选择哪一个呢?

答案很简单,把两个规则的移动位数都算出来,选择移动位数多的就是了。

这里 p 是坏字符,并且不存在好后缀,所以采用坏字符的规则,移动 2 位。

12、



这个时候,我们可以发现,模式串的字符全部都匹配了,这也意味着匹配结束了。

总结

这篇文章我是采用直接举例子的方式来讲,我觉得这样反而容易懂,并且在讲的过程中,可能没有讲的那么全,这是因为我不想说的太全,因为把所有情况都罗列处理的话,相信你容易晕。所以我才用这种方式,让你先懂了这个 BM 的算法思想,之后的细节,你可以再去琢磨。

为了讲清楚这个算法,也算是绞尽脑汁,特别是为了能够以最简单的方式来讲解好后缀的规则,停笔思索了好久,最后也百度搜索了几篇文章,看看别人都怎么讲,还翻开了我之前购买的数据结构与算法的专栏,,,最后结合自己的想法写了出来。希望这篇文章,能够让你读懂给 BM 算法,这个算法的核心就是坏字符和好后缀了,相信你一定能够搞懂!后面会连续讲解几篇与有关的文章。

如果你觉得这篇内容对你挺有启发,为了让更多的人看到这篇文章:不妨

1、点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)

2、关注我和专栏,让我们成为长期关系

3、关注公众号「苦逼的码农」,主要写算法、计算机基础之类的文章,里面已有100多篇原创文章



大部分的数据结构与算法文章被各种公众号转载相信一定能让你有所收获



我也分享了很多视频、书籍的资源,以及开发工具,欢迎各位的关注我的公众号:苦逼的码农,第一时间阅读我的文章。

字符串匹配Boyer-Moore算法:文本编辑器中的查找功能是如何实现的?---这应该讲的最容易懂的文章了!的更多相关文章

  1. 如何在文本编辑器中实现搜索功能? 字符串比较算法 BF算法 RK算法

    1.暴力比较 BF算法 2.比较字串hash值 RK算法 //字符串匹配 public class StringCmp { //约定:A主串长 n ,B模式串 长m.要求:在A串中找到B串匹配的下标 ...

  2. 字符串匹配的 Boyer-Moore 算法

    上一篇文章,我介绍了 字符串匹配的KMP算法 但是,它并不是效率最高的算法,实际采用并不多.各种文本编辑器的” 查找” 功能(Ctrl+F),大多采用 Boyer-Moore 算法. 下面,我根据 M ...

  3. 算法——字符串匹配之BM算法

    前言 Boyer-Moore算法是一种基于后缀匹配的模式串匹配算法(简称BM算法),后缀匹配就是模式串从右到左開始比較,但模式串的移动依旧是从左到右的.在实践中.BM算法效率高于前面介绍的<KM ...

  4. 字符串匹配与KMP算法实现

    >>字符串匹配问题 字符串匹配问题即在匹配串中寻找模式串是否出现, 首先想到的是使用暴力破解,也就是Brute Force(BF或蛮力搜索) 算法,将匹配串和模式串左对齐,然后从左向右一个 ...

  5. JavaScript Iframe富文本编辑器中的光标定位

    最近在项目中碰到一个比较棘手的问题: 在iframe富文本编辑器中,有个工具栏,这个工具栏在iframe标签之外,工具栏上有一个按钮,点击该按钮向iframe正在编辑中的光标处插入一个图片,图片会插入 ...

  6. 实现字符串匹配的KMP算法

    KMP算法是Knuth-Morris-Pratt算法的简称,它主要用于解决在一个长字符串S中匹配一个较短字符串s. 首先我们从整体来把我这个算法的思想. 字符串匹配的朴素算法: 我们容易想到朴素算法, ...

  7. Luogu 3375 【模板】KMP字符串匹配(KMP算法)

    Luogu 3375 [模板]KMP字符串匹配(KMP算法) Description 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来 ...

  8. 字符串匹配的 KMP算法

    一般字符串匹配过程 KMP算法是字符串匹配算法的一种改进版,一般的字符串匹配算法是:从主串(目标字符串)和模式串(待匹配字符串)的第一个字符开始比较,如果相等则继续匹配下一个字符, 如果不相等则从主串 ...

  9. Hash——字符串匹配(求s1在s2中出现的次数)

    题目描述: 这是一道模板题. 给定一个字符串 A 和一个字符串 B ,求 B 在 A  中的出现次数.A 和 B中的字符均为英语大写字母. 求A 在 B 中出现了几次.(可重叠) 样例输入: 3 BA ...

随机推荐

  1. 创建 DLL 步骤 和 SRC

    LIBRARY SimulationTouchDll EXPORTS MouseControl GetPosition //MouseControlInterface.def 文件 #pragma o ...

  2. delphi2009(10,xe)下indy10发送utf8字符串

    最近实现一个功能,使用delphi2009以TCP调用Java端的接口,接口要求先发送字符串的长度,然后再发送字符串内容,并且字符串要求是utf8格式的 调试了好长时间,才终于发现解决办法,或者说发现 ...

  3. XE Delphi 判断字符为中文的方法

    在uses中添加System.AnsiStrings /// Param ch--字符串/// Param cno--字符位置 function IsZHChar(const ch: AnsiStri ...

  4. PHP获得指定日期所在星期的第一天和最后一天

    function getdays($day){ $lastday=date('Y-m-d',strtotime("$day Sunday")); $firstday=date('Y ...

  5. win10 uwp ApplicationView

    原文:win10 uwp ApplicationView 本文和大家介绍一个重要的类,他可以用来设置窗口,如设置启动大小,设置是否允许截图,是否进入全屏,所有和窗口有关的,都可以在他这里设置. 可以使 ...

  6. 零元学Expression Blend 4 - Chapter 14 用实例了解布局容器系列-「Pathlistbox」II

    原文:零元学Expression Blend 4 - Chapter 14 用实例了解布局容器系列-「Pathlistbox」II 本章将延续上一章的范例,步骤解析. 本章将延续上一章的范例,步骤解析 ...

  7. WP 8.1 中挂起时页面数据保存方式(1)

    1.保存到Applicaion Data配置信息中: 保存: privatevoid testTB_TextChanged(object sender, TextChangedEventArgs e) ...

  8. DELPHI美化界面(2009开始TPanel增加了ParentBackGround)

    1.透明问题. 要重新调整界面确实很麻烦,以前用DELPHI开发的界面都很土,和WEB真是没办法比.(我以前用的是DELPHI7),现在回想起来,DELPHI难做的原因是:没有透明控件.所有控件都是不 ...

  9. How to create my own self signed certificate chain?

    --Refer to https://superuser.com/questions/126121/how-to-create-my-own-certificate-chain for detail. ...

  10. 如何把zip文件直接解压到内存里?

    解压到硬盘再读进来耽误时间. var  LZip: TZipFile;  LMem: TMemoryStream;  LBytes: TBytes;begin  LZip := TZipFile.Cr ...