WM算法--多模式匹配
来源:互联网 发布:云计算实验室建设方案 编辑:程序博客网 时间:2024/05/01 23:15
WM算法详解
WM算法采用字符块技术,增大了主串和模式串不匹配的可能性,从而增加了直接跳跃的机会。使用散列表选择模式串集合中的一个子集与当前文本进行完全匹配。使用前缀表进一步过滤不匹配的模式串,使算法获得了较高的运行效率。
WM算法首先对模式串集合进行预处理。预处理阶段将建立3个表格:SHIFT表,HASH表和PREFIX表。SHIFT表用于在扫描文本串的时候,根据读入字符串决定可以跳过的字符数,如果相应的跳跃值为0,则说明可能产生匹配。HASH表用来存储尾块字符散列值相同的模式串。PREFIX表用于存储尾块字符散列值相同的模式串的首块字符散列值。
假设模式串集合P中最短的模式长度为m,那么,后续仅考虑所有模式的前m个字符组成的模式串。
设X=x1…xB为T中的待比较的长度为B的子串,通过hash函数映像得到一个索引值index,以该索引值作为偏移得到SHIFT表中的值,该值决定读到当前子串x后可以跳过的位数。假设X映射到SHIFT表的入口为index的表项,即index=hash(x)。
SHIFT表中值的计算原则为:
(1) 如果X不出现在模式串中,则SHIFT[h]=m-B+1。
(2) 如果X出现在某些模式串中,而且在所有的模式串中的最右出现位置为q,则SHIFT[h]=m-q。
算法匹配的大致原理:
(1) 设当前比较的文本串X的hash值为h。如果SHIFT[h]=0,说明可能产生了匹配,那么需要进一步的判断。
(2) 用该h值作为索引,查HASH表找到HASH[h],它存储的是指标,指向两个单独的表:一个是模式链表,另一个是PREFIX表。模式链表中存放的是后B个字符的hash值同为h的所有模式。
(3) 对于待比较长度为m的串,如果其长度为B的前缀与模式的前缀的hash值也相同,则再将相应的文本串与符合的模式逐一进行比较,最终判定是否完全匹配。
算法匹配的主要过程:
基于后缀的模式匹配,每次扫描B个字符T[m-B+1]…..T[m]。
(1) 扫描text的末B位T[m-B+1]…..T[m]通过hash function计算其哈希值h。
(2) 查表,SHIFT[h]>0,text小指针后滑SHIFT[h]位,执行(1);SHIFT[h]=0,执行那个(3)。
(3) 计算此m位text的前缀的哈希值,记为text_prefix。
(4) 对于每个p(HASH[h]≦p<HASH[h+1]),看是否PREFIX[p]=text_prefix。
(5) 如果相等,让真正的模式串去和text匹配。
WM算法的代码网上已经有了,下面给出其中的一个参
考:
http://www.nhs8.com/index.php/post/1338.htm
l
这段代码对于初学者可能还是比较的晦涩,下面给出
对这份代码的详细注释以及流程图。
首先给出的是对代码的详细注释:
#ifndef WM_H
#define WM_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASHTABLESIZE (256*256)
#define MAXLEN 256
typedef struct wm_pattern_struct//每个模式串的结构
{
struct wm_pattern_struct *next;//指向下一个模式串
unsigned char *psPat; //pattern array//模式串数组
unsigned psLen; //length of pattern in bytes//模式串的长度
}WM_PATTERN_STRUCT;
#define HASH_TYPE short
#define SHIFTTABLESIZE (256*256)
typedef struct wm_struct//模式串集的结构
{
WM_PATTERN_STRUCT *plist; //pattern list//模式串列表
WM_PATTERN_STRUCT *msPatArray; //array of patterns//模式串转变为WM _PATTERN_STRUCT后的结构
unsigned short *msNumArray; //array of group counts, # of patterns in each hash group
int msNumPatterns; //number of patterns loaded//模式串的个数
unsigned msNumHashEntries;//HASH表的大小
HASH_TYPE *msHash; //last 2 characters pattern hash table//HASH表
unsigned char* msShift; //bad word shift table//SHIFT表
HASH_TYPE *msPrefix; //first 2 characters prefix table//PREFIX表
int msSmallest; //shortest length of all patterns//最短模式串的长度
}WM_STRUCT;
WM_STRUCT * wmNew();
void wmFree(WM_STRUCT *ps);
int wmAddPattern(WM_STRUCT *ps,unsigned
char *P,int m);
int wmPrepPatterns(WM_STRUCT *ps);
void wmSearch(WM_STRUCT *ps,unsigned char
*Tx,int n);
#endifWM.c文件如下:view plaincopy to
clipboardprint?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "wm.h"
extern int nline=1;
extern int nfound=0;
#define MAXN 10001 //模式串的最大长度MAXN –
1
#define MAXM 51//单词最大长度为MAXM – 1
WM_STRUCT * wmNew()
{
WM_STRUCT *p=(WM_STRUCT *)malloc(sizeof
(WM_STRUCT));
if(!p) return 0;
p->msNumPatterns=0;
p->msSmallest=1000;
return p;
}
void wmFree(WM_STRUCT *ps)
{
if(ps->msPatArray)
{
if(ps->msPatArray->psPat) free(ps-
>msPatArray->psPat);
free(ps->msPatArray );
}
if(ps->msNumArray) free(ps->msNumArray);
if(ps->msHash) free(ps->msHash);
if(ps->msPrefix) free(ps->msPrefix);
if(ps->msShift) free(ps->msShift);
free(ps);
}
int wmAddPattern(WM_STRUCT *ps,unsigned
char *q,int m)//m字符串长度,模式串转变为
WM_STRUCT结构
{
/>WM_PATTERN_STRUCT *p;
p=(WM_PATTERN_STRUCT *)malloc(sizeof
(WM_PATTERN_STRUCT));
if(!p) return -1;
p->psPat=(unsigned char*)malloc(m+1);
memset(p->psPat+m,0,1); //模式串最后一位位0,
结束标志
memcpy(p->psPat,q,m);
p->psLen=m;
ps->msNumPatterns++;
if(p->psLen<(unsigned)ps->msSmallest) ps-
>msSmallest=p->psLen;
p->next=ps->plist; 有点从后往前插入链表的感觉
ps->plist=p;
return 0;
}
static unsigned HASH16(unsigned char *T)
{
return (unsigned short) (((*T)<<8) | *(T+1));
}
void sort(WM_STRUCT *ps)//字符串哈希值从小到大
排列
{
int m=ps->msSmallest;
int i,j;
unsigned char *temp;
int flag; //该值的作用是,当某一时刻的序列已经从小
到大排列时,就无须再进行扫描了
for(i=ps->msNumPatterns-1,flag=1;i>0 &&
flag;i–) //以下为冒泡排序算法
{
flag=0;
for(j=0;j<i;j++)
{
if(HASH16(&(ps->msPatArray[j+1].psPat[m-
2]))<HASH16(&(ps->msPatArray[j].psPat[m-2])))
{
flag=1;
temp=ps->msPatArray[j+1].psPat;
ps->msPatArray[j+1].psPat=ps->msPatArray
[j].psPat;
ps->msPatArray[j].psPat=temp;
}
}
}
}
static void wmPrepHashedPatternGroups
(WM_STRUCT *ps)//计算有多少个不同哈希值,且从
小到大
{
unsigned sindex,hindex,ningroup;
int i;
int m=ps->msSmallest;
ps->msNumHashEntries=HASHTABLESIZE;
ps->msHash=(HASH_TYPE*)malloc(sizeof
(HASH_TYPE)* ps->msNumHashEntries);
if(!ps->msHash)
{
printf("No memory in
wmPrepHashedPatternGroups()\n");
return;
}
for(i=0;i<(int)ps->msNumHashEntries;i++)
{
ps->msHash[i]=(HASH_TYPE)-1;
}
for(i=0;i<ps->msNumPatterns;i++)
{
hindex=HASH16(&ps->msPatArray[i].psPat[m-
2]);
sindex=ps->msHash[hindex]=i;
ningroup=1;
//此时哈希表已经有序了
while((++i<ps->msNumPatterns) &&
(hindex==HASH16(&ps->msPatArray[i].psPat
[m-2])))
ningroup++;
ps->msNumArray[sindex]=ningroup;
i–;
}
}
static void wmPrepShiftTable(WM_STRUCT
*ps)//建立shift表,算出每个字符块要移动的距离,像
Horspool算法那样的
{
int i;
unsigned short m,k,cindex;
unsigned shift;
m=(unsigned short)ps->msSmallest;
ps->msShift=(unsigned char*)malloc
(SHIFTTABLESIZE*sizeof(char));
if(!ps->msShift)
return;
for(i=0;i<SHIFTTABLESIZE;i++)
{
ps->msShift[i]=(unsigned)(m-2+1);
}
for(i=0;i<ps->msNumPatterns;i++)
{
for(k=0;k<m-1;k++)
{
shift=(unsigned short)(m-2-k);
cindex=((ps->msPatArray[i].psPat[k]<<8) | (ps-
>msPatArray[i].psPat[k+1]));//B为2
if(shift<ps->msShift[cindex])
ps->msShift[cindex]=shift;//k=m-2时,shift=0,
}
}
}
static void wmPrepPrefixTable(WM_STRUCT
*ps)//建立Prefix表
{
int i;
ps->msPrefix=(HASH_TYPE*)malloc(sizeof
(HASH_TYPE)* ps->msNumPatterns);
if(!ps->msPrefix)
{
printf("No memory in wmPrepPrefixTable()\n");
return;
}
for(i=0;i<ps->msNumPatterns;i++)
{
ps->msPrefix[i]=HASH16(ps->msPatArray
[i].psPat); //对每个模式串的前缀进行哈希
}
}
void wmGroupMatch(WM_STRUCT *ps,//后缀哈希
值相同,比较前缀以及整个字符匹配
int lindex, //lindex为后缀哈希值相同的那些模式串中
的一个模式串的index
unsigned char *Tx,
unsigned char *T)
{
WM_PATTERN_STRUCT *patrn;
WM_PATTERN_STRUCT *patrnEnd;
// int text_prefix;
HASH_TYPE text_prefix; //changed by dklkt
unsigned char *px,*qx;
patrn=&ps->msPatArray[lindex];
patrnEnd=patrn+ps->msNumArray[lindex]; //哈
希值相同
text_prefix=HASH16(T);
for(;patrn<patrnEnd;patrn++)
{
if(ps->msPrefix[lindex++]!=text_prefix)
continue;
else
{
px=patrn->psPat;
qx=T;
while(*(px++)==*(qx++) && *(qx-1)!=’\0′); //
整个模式串进行比较
if(*(px-1)==’\0′)
{
printf("Match pattern "%s" at line %d column
%d\n",patrn->psPat,nline,T-Tx+1);
nfound++;
}
}
}
}
int wmPrepPatterns(WM_STRUCT *ps)//由plist得
到msPatArray
{
int kk;
WM_PATTERN_STRUCT *plist;
ps->msPatArray=(WM_PATTERN_STRUCT*)
malloc(sizeof(WM_PATTERN_STRUCT)*ps-
>msNumPatterns);
if(!ps->msPatArray)
return -1;
ps->msNumArray=(unsigned short*)malloc
(sizeof(short)*ps->msNumPatterns);
if(!ps->msNumArray)
return -1;
for(kk=0,plist=ps->plist;plist!=NULL &&
kk<ps->msNumPatterns;plist=plist->next)
{
memcpy(&ps->msPatArray[kk++],plist,sizeof
(WM_PATTERN_STRUCT));
}
sort(ps);
wmPrepHashedPatternGroups(ps);
wmPrepShiftTable(ps);
wmPrepPrefixTable(ps);
return 0;
}
void wmSearch(WM_STRUCT *ps,unsigned char
*Tx,int n)//字符串查找
{
int Tleft,lindex,tshift;
unsigned char *T,*Tend,*window;
Tleft=n;
Tend=Tx+n;
if(n<ps->msSmallest)
return;
//T--------窗口-------Window
for(T=Tx,window=Tx+ps->msSmallest-
1;window<Tend;T++,window++,Tleft–)
{
tshift=ps->msShift[(*(window-1)<<8) |
*window];
while(tshift) //此时tshift!=0,无匹配
{
window+=tshift;
T+=tshift;
Tleft-=tshift;
if(window>Tend) return;
tshift=ps->msShift[(*(window-1)<<8) |
*window];
}
//tshift=0,表明后缀哈希值已经相同
if((lindex=ps->msHash[(*(window-1)<<8) |
*window])==(HASH_TYPE)-1) continue;
lindex=ps->msHash[(*(window-1)<<8) |
*window];
wmGroupMatch(ps,lindex,Tx,T); //后缀哈希值相同
,比较前缀及整个模式串
}
}
int main()
{
int length,n;
WM_STRUCT *p;
char keyword[MAXM]; //单词
char str[MAXN]; //模式串
p=wmNew();
printf("scanf the number of words–>\n");
scanf("%d", &n);
printf("scanf the words–>\n");
while(n –)
{
scanf("%s", keyword);
length=strlen(keyword);
wmAddPattern(p,keyword,length);
}
wmPrepPatterns(p);
printf("scanf the text string–>\n");
scanf("%s", str);
length=strlen(str);
wmSearch(p,str,length);
wmFree(p);
return(0);
}
下面部分为程序代码的流程图,有助于更好的理解上面的程序
Main()
{
WM_STRUCT* p=wmNew();--->(1)
While(n--)
wmAddPattern(p,keyword,klength);--->(2)
wmPrepPatterns(p);---->(3)
wmSearch(p,str,slength);----->(8)
wmFree(p);---->(10)
}
(1) new(p)以及p的初始化
(2) keyword-----add-->p->list
(3) plist---得到->msPatArray
sort(ps);-->(4)
wmPrepHashedpatternsGroup(ps);-->(5)
wmPrepShiftTable(ps);-->(6)
wmPrepPrefixTable(ps);--->(7)
(4) 冒泡排序,字符串哈希值从小到大排列
(5) HASH表初始化
计算有多少个不同哈希值,且从小到大
拉链:
(6) 构建SHIFT表
SHIFT[index]= m-B+1;//无匹配
min(shift);//最短移动距离
(7) 构建PREFIX表
Ps->msPrefix[i]=HASH16(ps->msPatArray[i].psPat);
(8) 求tshift
若tshift!=0 移动tshift
若tshift=0 hash值不存在,continue;
wmGroupMatch--->(9)
(9) for(;patrn<patrnEnd;patrn++)
比较ps->msprefix[index++]和text_prefix
若相等,再比较整个模式串
(10) free(p)
- WM算法--多模式匹配
- WM多模式匹配算法
- 多模式匹配算法:AC算法、WM算法
- WM多模式字符串匹配
- WM算法原理与代码实现(模式匹配)
- 多模式匹配算法
- 多模式匹配算法
- 多模式匹配算法
- wm算法
- AC 多模式匹配算法
- AC算法,多模式匹配
- AC多模式匹配算法
- 多模式匹配AC算法
- 多模式匹配算法-AC算法
- 多模式字符串匹配算法---ac算法
- 多模式匹配算法-AC算法等
- 一种快速的多模式匹配算法
- Wu-Manber 经典多模式匹配算法
- pppoe中的mtu与mss
- c/c++: 多线程编程基础讲解(五)
- Android上成功实现了蓝牙的一些Profile
- LIST CONTROL
- 为什么写技术博客对新人如此重要?
- WM算法--多模式匹配
- Flex中ToggleButtonBar控件设置button的样式
- TCP/IP通信程序设计的丰富多样性
- Apache Beanutils基本用法
- jquery UI框架界面演试文档
- 【OpenCV】cv::Mat与IplImage类型转换
- Iframe正在加载时显示遮罩层
- SqlServer 系统静态函数
- ci service 和catalog.wci是什么?