python实现wm算法(多模式匹配)

唔……项目的一部分,留个底吧。
首先介绍一下wm算法:
这是一个多模式匹配算法,核心思想是跳步——简单的说,就是如何找出当前状态下,跳的最多步数。
为了完成这样一个需求,要先对数据进行处理。
这里,我们假设要匹配的短字符为tag,要匹配的内容为text
打个比方:

listtag = ['陈白露呀', '杜伟的死', '以色列外交部']
listext = [text0, text1, text2, text3, text4, text5, text6]
text0 = '【外媒:中国驻以色大使去世,原因尚不明确】以色列' \
            '本国的多家媒体也都报道了此事。其中,根据以色列《国土报》(Haaretz)的说法,' \
            '杜伟的死因疑为心脏病发作,成为中国驻以色大使,中国驻以色大使馆的信息显示,' \
            '就在5月12日,杜伟还曾与以色列外交部主管多边事务的副总司长巴尔举行视频会议。'
text1 = '以色列大使'
text2 = '【多家以色列媒体密集报道中国大使“突然去世”,中国使馆尚未证实】以色列《耶路撒冷邮报》、' \
            '《以色列时报》等多家媒体刚刚消息称,以色列外交部官员证实,中国驻以大使杜伟于当地时间' \
            '17日早晨被发现死在其位于特拉维夫郊区赫兹利亚的官邸中。目前暂未看到中国驻以色列大使馆证实' \
            '此事。报道称,警察目前正在就死因进行调查。报道还称,中国驻以色列大使馆表示目前暂无法确认相' \
            '关报道。另据路透社报道,以色列12频道电视台援引身份未经证实的多名现' \
            '场紧急医务官说法称,中国大使是在睡梦中因自然原因去世。《耶路撒冷邮报》还援引' \
            '以色列陆军广播电台(Army Radio)报道称,现场无暴力迹象,以色列大使' \
            '调查人认为杜伟是因心脏病去世。《耶路撒冷邮报》称,以色列外交部已就中国大使突然去世向中方表示哀悼。'
text3 = '#朗朗朗当爸#神奇的吃法'
text4 = '#给黄瓜挤奶嗯????什么骚操作'
text5 = '陈白露呀好可惜啊'
text6 = '李光洁'

【阿西,随便去微博摘了点+私货】
首先,我们要寻找最小的tag长度,这里是‘杜伟的死’,四个字符。
然后,再假定一个块的大小,俗称B值(一般为2)
我们就可以得到所有的前缀:
‘陈白’,‘白露’,‘露呀’
‘杜伟’,‘伟的’,‘的死’
‘以色’,‘色列’,‘列外’
每个tag的前缀数 = 最小的长度 - numb + 1
因为我用的是python(python,永远的神!),所以可以很容易的映射每个前缀对应的跳步数
跳步数 = 最小长度 - 前缀最后一个字符的角标 - 1
比如,陈白 的跳步数 4 - 1 - 1= 2
白露 的跳步数 4 - 2 - 1 = 1
露呀 4 - 3 - 1 = 0
这里需要注意,如果存在相同的前缀,取最小的那个
【简单的讲,就是如果取大了容易漏】
这里就涉及到另一个结构了。
另一个结构就是前缀对应的tag
【讲道理,这其实不是前缀,但……后缀也不合适,中缀??】
这里我们只找对应跳步数为0的前缀
比如 ‘露呀’,‘的死’,‘列外’
‘露呀’对应的tag是——‘陈白露呀’
‘的死’对应的tag是——‘杜伟的死’
‘列外’对应的是tag是——‘以色列外交部’
只要找到跳步数为0的前缀【就是不用再跳了】,就开始匹配前文后文是否和tag完全相同,如果相同,抓到你了,输出之!
特殊情况就是,比如一个前缀对应了两个tag
比如
‘郎朗当爸’
‘光洁当爸’
前缀都是 当爸 跳步数都为0,那么 当爸 对应一个列表,每次找到都要匹配两遍
这就比较麻烦了,如果有一天大家都当爸了,匹配的难度会成倍增加
所以,要引入另一个结构,真·前缀
这个结构就是,如果出现重复前缀,那它对应的列表不是tag,而是tag的前两个字符
还是上面的那个例子
‘当爸’ ——【‘郎朗’,‘光洁’】
其中,郎朗 对应——‘郎朗当爸’
光洁 对应——‘光洁当爸’
这样就规避掉这个问题了
【不过,因为我这个项目做得是寻找敏感词,重复的比较少,这里没有实现,就写一写原理嘻嘻】
唔……准备工作做好,我们就开始跳了!
开始抓前缀!
从第一个字符开始,两个两个匹配,如果它没有出现在字符集里,跳最小长度(这里为4)
如果出现了,查找跳步数词典,除了0都按跳步数来
如果出现了且是0,那么就要考虑比较前后文了,如果先后文相同,输出,不同则后跳一位。
如果出现前缀对应的是列表的情况,进行逐个比较——或者写一个真·前缀结构,再匹配一次前缀,这里我就没实现了。
然后上代码!

class wm:

   def get_appear_list(self, listtag, listext):
       listappear = []
       listmin = []
       temp = 0  # 计算最短前缀长度所用临时变量
       min = len(listtag[0])  # 前缀长度
       for key in listtag:
           if len(key) > 3:
               temp = len(key)
               if temp < min:
                   min = temp
           else:
               listmin.append(key)
       numB = 2  # 块的大小
       num = min - numB + 1  # 根据B和最短tag长,计算出的后缀数
       i = 0
       temp1 = listtag[0][i] + listtag[0][i + 1]  # 计算shift值所用临时变量
       dictshift = {temp1: (min - i - 2)}  # shift字典,结构为{双字符:shift值}
       dictprtterns = {}
       i += 1  # 计数的
       j = 0
       m = 0  # 计算的最小shift值
       for key in listtag:
           while i < num:
               temp1 = key[i] + key[i + 1]
               m = min - i - 2
               if temp1 in dictshift:
                   if m < dictshift[temp1]:
                       dictshift[temp1] = m
                   else:
                       pass
               dictshift[temp1] = m
               if m == 0:
                   if temp1 not in dictshift:
                       dictprtterns[temp1] = key
                   else:
                       dictprtterns.setdefault(temp1, []).append(key)
               i += 1
           i = 0
       for key in listext:
           tagget = key
           i = min - 2
           while i < len(tagget) - 1:
               temp1 = tagget[i] + tagget[i + 1]
               if temp1 in dictshift:
                   if dictshift[temp1] > 0:
                       i += dictshift[temp1]
                   else:
                       length = len(dictprtterns[temp1])
                       temp2 = 0
                       temp4 = 0
                       while temp4 < length:
                           flag = 0
                           j = i - min + 2
                           if dictprtterns[temp1][temp4] == tagget[j:j + len(dictprtterns[temp1][temp4])]:
                               if dictprtterns[temp1][temp4] not in listappear:
                                   listappear.append(dictprtterns[temp1][temp4])
                               flag = 1
                               break
                           temp4 += 1
                       if flag == 0:
                           i += 1
                       else:
                           i += min
               else:
                   i += min
       return listappear

这里返回的是出现过的字符,也可以修改条件,改成输出每个tag出现的次数之类的,原理差不多。

问题!

上面这个实现方式有个原则问题——因为它的原理是寻找跳步数,所以……
tag的长度必须大于3!
如果小于3,那暴力遍历没啥区别,而且会丢tag
好吧,英文随便一个单词就大于三个字符了,但中文不行
然后我的鬼才小队友想了一个办法,把所有字符转码成utf-8,这样就够长了。
代码就不放了,加个函数转化就行

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值