字符串匹配算法-BM
在用于查找子字符串的算法中,BM(Boyer-Moore)算法是当前有效且应用比较广泛的一种算法,各种文本编辑器的“查找”功能(Ctrl+F),大多采用Boyer-Moore算法。比我们学习的KMP算法快3~5倍。
在1977年,Boyer-Moore算法由德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明
下面通过Java实现BM算法:
package com.buaa; import java.util.Random; /**
* @ProjectName StringPatternMatchAlgorithm
* @PackageName com.buaa
* @ClassName BM
* @Description TODO
* @Author 刘吉超
* @Date 2016-05-26 22:26:08
*/
public class BM {
/**
* 利用坏字符规则计算移动位数
*/
public static int badCharacter(String moduleString, char badChar,int badCharSuffix){
return badCharSuffix - moduleString.lastIndexOf(badChar, badCharSuffix);
} /**
* 利用好后缀规则计算移动位数
*/
public static int goodCharacter(String moduleString,int goodCharSuffix){
int result = -1;
// 模式串长度
int moduleLength = moduleString.length();
// 好字符数
int goodCharNum = moduleLength -1 - goodCharSuffix; for(;goodCharNum > 0; goodCharNum--){
String endSection = moduleString.substring(moduleLength - goodCharNum, moduleLength);
String startSection = moduleString.substring(0, goodCharNum);
if(startSection.equals(endSection)){
result = moduleLength - goodCharNum;
}
} return result;
} /**
* BM匹配字符串
*
* @param originString 主串
* @param moduleString 模式串
* @return 若匹配成功,返回下标,否则返回-1
*/
public static int match(String originString, String moduleString){
// 主串
if (originString == null || originString.length() <= 0) {
return -1;
}
// 模式串
if (moduleString == null || moduleString.length() <= 0) {
return -1;
}
// 如果模式串的长度大于主串的长度,那么一定不匹配
if (originString.length() < moduleString.length()) {
return -1;
} int moduleSuffix = moduleString.length() -1;
int module_index = moduleSuffix;
int origin_index = moduleSuffix; for(int ot = origin_index; origin_index < originString.length() && module_index >= 0;){
char oc = originString.charAt(origin_index);
char mc = moduleString.charAt(module_index);
if(oc == mc){
origin_index--;
module_index--;
}else{
// 坏字符规则
int badMove = badCharacter(moduleString,oc,module_index);
// 好字符规则
int goodMove = goodCharacter(moduleString,module_index);
// 下面两句代码可以这样理解,主串位置不动,模式串向右移动
origin_index = ot + Math.max(badMove, goodMove);
module_index = moduleSuffix;
// ot就是中间变量
ot = origin_index;
}
} if(module_index < 0){
// 多减了一次
return origin_index + 1;
} return -1;
} /**
* 随机生成字符串
*
* @param length 表示生成字符串的长度
* @return String
*/
public static String generateString(int length) {
String baseString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; StringBuilder result = new StringBuilder(); Random random = new Random();
for (int i = 0; i < length; i++) {
result.append(baseString.charAt(random.nextInt(baseString.length())));
} return result.toString();
} public static void main(String[] args) {
// 主串
// String originString = generateString(10);
String originString = "HERE IS A SIMPLE EXAMPLE";
// 模式串
// String moduleString = generateString(4);
String moduleString = "EXAMPLE";
// 坏字符规则表
// int[] badCharacterArray = badCharacter(originString,moduleString); System.out.println("主串:" + originString);
System.out.println("模式串:" + moduleString); int index = match(originString, moduleString);
System.out.println("匹配的下标:" + index);
}
}
下面,我来解释上面代码
首先先明确两个规则:坏字符规则、好后缀规则
1、坏字符规则
后移位数 = 坏字符的位置 - 模式串中的坏字符上一次出现位置
如果"坏字符"不包含在模式串之中,则上一次出现位置为 -1。以下面这两个字符串为例

因为"P"与"E"不匹配,所以"P"被称为"坏字符",它出现在模式串(模式串就是EXAMPLE)的第6位(从0开始编号),在模式串中的上一次出现位置为4,所以后移 6 - 4 = 2位
2、好后缀规则
后移位数 = 好后缀的位置 - 模式串中的上一次出现位置
举例来说,如果模式串"ABCDAB"的后一个"AB"是"好后缀"。那么它的位置是5(从0开始计算,取最后的"B"的值),在模式串中的上一次出现位置是1(第一个"B"的位置),所以后移 5 - 1 = 4位,前一个"AB"移到后一个"AB"的位置。
再举一个例子,如果模式串"ABCDEF"的"EF"是好后缀,则"EF"的位置是5 ,上一次出现的位置是 -1(即未出现),所以后移 5 - (-1) = 6位,即整个字符串移到"F"的后一位。
这个规则有三个注意点:
(1)"好后缀"的位置以最后一个字符为准。假定"ABCDEF"的"EF"是好后缀,则它的位置以"F"为准,即5(从0开始计算)。
(2)如果"好后缀"在模式串中只出现一次,则它的上一次出现位置为 -1。比如,"EF"在"ABCDEF"之中只出现一次,则它的上一次出现位置为-1(即未出现)。
(3)如果"好后缀"有多个,这时应该选择最长的那个"好后缀"且它的上一次出现位置必须在头部。比如,假定"BABCDAB"的"好后缀"是"DAB"、"AB"、"B",这时"好后缀"的上一次出现位置是什么?回答是,此时采用的好后缀是"B",它的上一次出现位置是头部,即第0位,其他好后缀上一次出现的位置都不在头部
规则讲完啦,接下说一下上面代码
1、假定主串为"HERE IS A SIMPLE EXAMPLE",模式串为"EXAMPLE",模式串也就是搜索词
|
主串 |
HERE IS A SIMPLE EXAMPLE |
|
模式串 |
EXAMPLE |
2、首先,主串与模式串头部对齐,从尾部开始比较。这是一个很聪明的想法,因为如果尾部字符不匹配,那么只要一次比较,就可以知道前7个字符(整体上)肯定不是要找的结果。我们看到,"S"与"E"不匹配。这时,"S"就被称为"坏字符"(bad character),这时用坏字符规则得到的是7,用好后缀规则得到的是-1,选择大的作为后移位数,这里选择7

3、依然从尾部开始比较,发现"P"与"E"不匹配,所以"P"是"坏字符"。

4、这时用坏字符规则得到的是2,用好后缀规则得到的是-1,选择大的作为后移位数,这里选择2

5、依然从尾部开始比较,"E"与"E"匹配。

6、比较前面一位,"LE"与"LE"匹配。

7、比较前面一位,"PLE"与"PLE"匹配

8、比较前面一位,"MPLE"与"MPLE"匹配。我们把这种情况称为"好后缀"(good suffix),即所有尾部匹配的字符串。注意,"MPLE"、"PLE"、"LE"、"E"都是好后缀

9、比较前一位,发现"I"与"A"不匹配。所以,"I"是"坏字符",这时用坏字符规则得到的是3,用好后缀规则得到的是6,选择大的作为后移位数,这里选择6

10、继续从尾部开始比较,"P"与"E"不匹配,因此"P"是"坏字符"。这时用坏字符规则得到的是2,用好后缀规则得到的是-1,选择大的作为后移位数,这里选择2

11. 从尾部开始逐位比较,发现全部匹配,于是搜索结束

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【刘超★ljc】。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
字符串匹配算法-BM的更多相关文章
- [转] 字符串模式匹配算法——BM、Horspool、Sunday、KMP、KR、AC算法一网打尽
字符串模式匹配算法——BM.Horspool.Sunday.KMP.KR.AC算法一网打尽 转载自:http://dsqiu.iteye.com/blog/1700312 本文内容框架: §1 Boy ...
- 字符串模式匹配算法——BM、Horspool、Sunday、KMP、KR、AC算法一网打尽
字符串模式匹配算法——BM.Horspool.Sunday.KMP.KR.AC算法一网打尽 本文内容框架: §1 Boyer-Moore算法 §2 Horspool算法 §3 Sunday算法 §4 ...
- BM和KMP字符串匹配算法学习
BM和KMP字符串匹配算法学习 分类: 研究与学习 字符串匹配BM(Boyer-Moore)算法学习心得 http://www.cnblogs.com/a180285/archive/2011/12/ ...
- 字符串匹配算法之BM算法
BM算法,全称是Boyer-Moore算法,1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法. BM算法定义了两个规则: ...
- 字符串模式匹配算法——BM、Horspool、Sunday、KMP、KR、AC算法
ref : https://dsqiu.iteye.com/blog/1700312 本文内容框架: §1 Boyer-Moore算法 §2 Horspool算法 §3 Sunday算法 §4 KMP ...
- 字符串匹配算法(二)-BM算法详解
我们在字符串匹配算法(一)学习了BF算法和RK算法,那有没更加高效的字符串匹配算法呢.我们今天就来聊一聊BM算法. BM算法 我们把模式串和主串的匹配过程,可以看做是固定主串,然后模式串不断在往后滑动 ...
- 图解BM(Boyer-Moore)字符串匹配算法+代码实现
简介 本篇文章主要分为两个大的部分,第一部分通过图解的方式讲解BM算法,第二部分则代码实现一个简易的BM算法. 基本概念 bm是一个字符串匹配算法,有实验统计,该算法是著名kmp算法性能的3-4倍,其 ...
- Boyer-Moore 字符串匹配算法
字符串匹配问题的形式定义: 文本(Text)是一个长度为 n 的数组 T[1..n]: 模式(Pattern)是一个长度为 m 且 m≤n 的数组 P[1..m]: T 和 P 中的元素都属于有限的字 ...
- KMP单模快速字符串匹配算法
KMP算法是由Knuth,Morris,Pratt共同提出的算法,专门用来解决模式串的匹配,无论目标序列和模式串是什么样子的,都可以在线性时间内完成,而且也不会发生退化,是一个非常优秀的算法,时间复杂 ...
随机推荐
- jQuery预加载插件
插件描述:jQuery Fadeloader的插件可以让你轻松实现预加载到您的网站或部分使用级联渐显效果来显示特定的内容块(例如,头> MENU>内容>页脚) jQuery Fa ...
- Metasploit渗透测试魔鬼训练营
首本中文原创Metasploit渗透测试著作,国内信息安全领域布道者和资深Metasploit渗透测试专家领衔撰写,极具权威性.以实践为导向,既详细讲解了Metasploit渗透测试的技术.流程.方法 ...
- uva 11168 - Airport
凸包+一点直线的知识: #include <cstdio> #include <cmath> #include <cstring> #include <alg ...
- 李洪强iOS开发之-环信02.3_具体接口讲解 - Apple Docs
http://www.easemob.com/apidoc/ios/chat3.0/annotated.html Apple Docs.
- 为什么手机连接wifi会显示已停用?
1.通常导致手机连接WiFi显示“已停用”故障的原因是由于无线路由器“安全模式”设置不当造成的,对此我们可以通过以下方法来解决: 2.根据无线路由器背面的信息(包括路由器IP地址,登陆用户名和密码), ...
- iOS设备下添加button的按下效果
在触屏上, button的按下效果用:active触发, 但是我发现iOS设备上:active效果并没有生效. :active pseudo-class doesn't work in mobile ...
- 监控持有sql和被堵塞的sql
Session 1: mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> update Client ...
- MySQL源码之两阶段提交
在双1的情况下,两阶段提交的过程 环境准备:mysql 5.5.18, innodb 1.1 version配置: sync_binlog=1 innodb_flush_log_at_trx_comm ...
- Http 状态码完整说明
在网站建设的实际应用中,容易出现很多小小的失误,就像mysql当初优化不到位,影响整体网站的浏览效果一样,其实,网站的常规http状态码的表现也是一样, 一些常见的状态码为: 200 - 服务器成功返 ...
- HDU-2562 奇偶位互换
http://acm.hdu.edu.cn/showproblem.php?pid=2562 奇偶位互换 Time Limit: 3000/1000 MS (Java/Others) Memor ...