,,浅析Python实现DFA算法

,,浅析Python实现DFA算法

DFA称为确定性有限自动机,即有限自动机。特征:有一组有限的状态和一些从一个状态通向另一个状态的边。每条边都标有一个符号,其中一个状态是初始状态,一些状态是最终状态。与不确定有限自动机不同,在DFA中,来自同一状态的两个边缘符号没有相同的符号。

一.概述二。匹配关键词三。算法实现3.1。建造仓库结构。匹配关键词3.3。完成代码四。其他用途4.1。添加通配符。

目录

计算机操作系统中的进程状态和切换可以看作是对DFA算法的一种近似理解。如下图所示,椭圆代表状态,状态之间的连接代表事件。过程的状态和事件是可确定的,并且可以是详尽的。

DFA算法有很多应用。在这里,我们将介绍它在关键字匹配中的应用。

一、概述

我们可以把每个文本片段看作一个状态。例如,匹配关键字可以分成五个文本段:Pi、匹配、匹配关闭、匹配关键字和匹配关键字。

[流程]:

初始状态为空,当事件“马”被触发时,会过渡到状态“马”;

触发事件“匹配”并转换到状态“匹配”;

以此类推,直到它改变到最后一个状态“匹配关键字”。

我们来考虑多个关键词的情况,比如“匹配算法”、“匹配关键词”、“信息抽取”。

可以看出,上图中的状态图类似于树形结构,也正是因为这种结构,DFA算法在关键字匹配上比关键字迭代法(for loop)更快。经常刷LeetCode的读者应该知道,树形结构的时间复杂度小于for循环。

For循环:

keyword_list=[]

对于['匹配算法','匹配关键字','信息提取']中的关键字:

如果“DFA算法”中的关键字与关键字匹配:

关键字_列表.追加(关键字)

for循环需要遍历关键字列表,随着关键字列表的扩展,需要的时间会越来越长。

DFA算法:在找“马”的时候,只会根据事件去特定的序列,比如“匹配关键词”,而不是“匹配算法”,所以遍历的次数比for loop少。下面给出了的具体实现。

[问]:那么如何构建状态图中所示的结构呢?

【答】:在Python中,我们可以使用dict数据结构。

state_event_dict={

马':

匹配':{

计算':{

法国':

' is_end': True

},

' is_end': False

},

关闭':{

键':{

单词':{

' is_end': True

},

' is_end': False

},

' is_end': False

},

' is_end': False

},

' is_end': False

},

字母':{

利息':{

烟雾':

拍':{

' is_end': True

},

' is_end': False

},

' is_end': False

},

' is_end': False

}

}

以嵌套字典为树结构,以键为事件,用is_end字段判断状态是否为最后一个状态。如果是最后一个状态,则停止状态转换,获取匹配的关键字。

【问】:如果关键词之间存在包含关系,比如“匹配关键词”和“匹配”,应该怎么做?

【答】:我们还是可以用is_end字段来表示关键字的结束,增加一个新的字段,比如is_continue,表示匹配还可以继续。此外,还可以通过查找is_end字段以外的其他字段来确定是否继续匹配。比如下面代码中的“match”除了is_end字段还有“off”,所以需要继续匹配。

state_event_dict={

马':

匹配':{

关闭':{

'键': {

'词': {

' is_end': True

},

' is_end': False

},

' is_end': False

},

' is_end': True

},

' is_end': False

}

}

接下来,我们来实现这个算法。

二、匹配关键词

使用Python 3.6版本实现,当然Python 3 .X都能运行。

三、算法实现

定义_生成_状态_事件_字典(关键字_列表:列表)-格言:

state_event_dict={}

# 遍历每一个关键词

对于关键字列表中的关键字:

当前事件=状态事件

长度=长度(关键字)

对于索引,枚举中的字符(关键字):

如果茶不在当前字典中:

next_dict={'is_end': False}

当前字典[char]=下一个字典

当前字典=下一个字典

否则:

下一个字典=当前字典[字符]

当前字典=下一个字典

如果索引==长度- 1:

current_dict['is_end']=True

返回状态_事件_字典

关于上述代码仍然有不少可迭代优化的地方,例如先对关键词列表按照字典序进行排序,这样可以让具有相同前缀的关键词集中在一块,从而在构建存储结构时能够减少遍历的次数。

3.1、构建存储结构

def match(state_event_dict: dict,content: str):

match_list=[]

state_list=[]

temp_match_list=[]

对于char_pos,char in enumerate(内容):

# 首先找到匹配项的起点

如果在状态事件字典中有字符:

状态列表附加(状态事件字典)

temp_match_list.append({

' start': char_pos,

匹配":"

})

# 可能会同时满足多个匹配项,因此遍历这些匹配项

对于索引,枚举中的状态(状态列表):

如果充电状态:

状态列表[索引]=状态[字符]

temp _ match _ list[index][' match ']=char

# 如果抵达匹配项的结尾,表明匹配关键词完成

if state[char]['is_end']:

match _ list。追加(复制。deepcopy(临时匹配列表[索引])

# 如果还能继续,则继续进行匹配

if len(state[char].keys())==1:

状态_列表. pop(索引)

临时_匹配_列表. pop(索引)

# 如果不满足匹配项的要求,则将其移除

否则:

状态_列表. pop(索引)

临时_匹配_列表. pop(索引)

返回匹配列表

3.2、匹配关键词

进口关于

导入副本

美术博士(Doctor of Fine Arts的缩写)级:

def __init__(self,keyword_list: list):

self.state_event_dict=self ._生成_状态_事件_字典(关键字_列表)

定义匹配(自身,内容:字符串):

match_list=[]

state_list=[]

temp_match_list=[]

对于char_pos,char in enumerate(内容):

如果茶在自我.状态_事件_字典中:

状态列表附加(自我状态事件字典)

temp_match_list.append({

' start': char_pos,

匹配":"

})

对于索引,枚举中的状态(状态列表):

如果充电状态:

状态列表[索引]=状态[字符]

temp _ match _ list[index][' match ']=char

if state[char]['is_end']:

match _ list。追加(复制。deepcopy(临时匹配列表[索引])

if len(state[char].keys())==1:

状态_列表. pop(索引)

临时_匹配_列表. pop(索引)

否则:

状态_列表. pop(索引)

临时_匹配_列表. pop(索引)

返回匹配列表

@静态方法

定义_生成_状态_事件_字典(关键字_列表:列表)-格言:

state_event_dict={}

对于关键字列表中的关键字:

当前事件=状态事件

长度=长度(关键字)

对于索引,枚举中的字符(关键字):

如果茶不在当前字典中:

next_dict={'is_end': False}

当前字典[char]=下一个字典

当前字典=下一个字典

否则:

下一个字典=当前字典[字符]

当前字典=下一个字典

如果索引==长度- 1:

current_dict['is_end']=True

返回状态_事件_字典

if __name__=='__main__ ':

dfa=DFA(['匹配关键词', '匹配算法', '信息抽取', '匹配'])

print(dfa.match('信息抽取之美术博士(美术博士的缩写)算法匹配关键词,匹配算法'))

输出:

[

{

'开始':0,

匹配":"信息抽取'

}, {

'开始':12,

匹配":"匹配'

}, {

'开始':12,

匹配":"匹配关键词'

}, {

'开始':18,

匹配":"匹配'

}, {

'开始':18,

匹配":"匹配算法'

}

]

3.3、完整代码

四、其他用法

在敏感词识别时往往会遇到同一种类型的句式,例如"你这个傻x”,其中X可以有很多,难道我们需要一个个添加到关键词表中吗?最好能够通过类似正则表达式的方法去进行识别。一个简单的做法就是"*",匹配任何内容。

添加通配符只需要对匹配关键词过程进行修改:

定义匹配(自身,内容:字符串):

match_list=[]

state_list=[]

temp_match_list=[]

对于char_pos,char in enumerate(内容):

如果茶在自我.状态_事件_字典中:

状态列表附加(自我状态事件字典)

temp_match_list.append({

' start': char_pos,

匹配":"

})

对于索引,枚举中的状态(状态列表):

is_find=False

state_char=无

# 如果是* 则匹配所有内容

如果' * '处于状态:

state_list[index]=state['*']

state_char=state['*']

is_find=True

如果充电状态:

状态列表[索引]=状态[字符]

state_char=状态[字符]

is_find=True

如果是_查找:

temp _ match _ list[index][' match ']=char

if state_char['is_end']:

match _ list。追加(复制。deepcopy(临时匹配列表[索引])

if len(state_char.keys())==1:

状态_列表. pop(索引)

临时_匹配_列表. pop(索引)

否则:

状态_列表. pop(索引)

临时_匹配_列表. pop(索引)

返回匹配列表

主()函数。

if __name__=='__main__ ':

dfa=DFA(['匹配关键词', '匹配算法', '信息*取', '匹配'])

print(dfa.match('信息抽取之美术博士(美术博士的缩写)算法匹配关键词,匹配算法,信息抓取'))

输出:

[

{

'开始':0,

匹配":"信息抽取'

}, {

'开始':12,

匹配":"匹配'

}, {

'开始':12,

匹配":"匹配关键词'

}, {

'开始':18,

匹配":"匹配'

}, {

'开始':18,

匹配":"匹配算法'

}, {

'开始':23,

匹配":"信息抓取'

}

]

以上就是浅析计算机编程语言实现美术博士(美术博士的缩写)算法的详细内容,更多关于Python DFA算法的资料请关注我们其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: