我试图用Python实现NFA来识别单词,但我的代码没有';不行,
我正在尝试实现一种识别单词的方法。我已经编写了以下代码,并尝试在纸上遵循我的代码,并使用示例输入一步一步地执行它,但我找不到我的代码没有执行我希望他执行的操作的原因。有人看到缺陷了吗?我看不到它,我对它为什么不起作用感到困惑我试图用Python实现NFA来识别单词,但我的代码没有';不行,,python,class,nfa,Python,Class,Nfa,我正在尝试实现一种识别单词的方法。我已经编写了以下代码,并尝试在纸上遵循我的代码,并使用示例输入一步一步地执行它,但我找不到我的代码没有执行我希望他执行的操作的原因。有人看到缺陷了吗?我看不到它,我对它为什么不起作用感到困惑 from collections import defaultdict class NFA: def __init__(self, initial, trns, final): self.initial = initial self
from collections import defaultdict
class NFA:
def __init__(self, initial, trns, final):
self.initial = initial
self.final = set(final)
self.trns = defaultdict(set)
for (src, char, tgt) in trns:
self.trns[src, char].add(tgt)
def recognizewords(self, strng):
strang = [char for char in strng]
strang.reverse()
visited = set()
agenda = [self.initial]
while strang and agenda:
currentletter = strang.pop()
current = agenda.pop()
visited.add(current)
if (current, currentletter) in self.trns.keys():
state = self.trns[(current, currentletter)]
for st in state:
if strang == [] and state in self.final:
return True
for i in self.trns[(current, currentletter)]:
agenda.append(i)
return False
exampleO = NFA(0, [(0,'o',1), (1,'k',2), (2,'i',1), (2,'!',3)], [3])
print(exampleO.recognizewords("ok!"))
它应该返回True,因为在某一点上我的列表“strang”将是空的(当我将currentletter指定给“!”),同时3是self.final,因为self.final对于我的对象来说是[3]。这并不能完全修复代码,因为这类问题的解决方案更容易可视化(至少对我来说)当您使用递归而不是显式堆栈时。正如我在评论中提到的,NFA实际上允许在给定的输入字符上转换到多个状态,尤其是空字符串。因此,我修改了输入规范,允许为每个转换指定一个新状态列表。此处,空字符串上的状态0转换为状态1或状态5(可识别
OK
)。状态2可在k
上转换为状态3或4
from collections import defaultdict
class NFA:
def __init__(self, initial, trns, final):
self.initial = initial
self.final = set(final)
self.trns = defaultdict(set)
self.epsilon_states = set()
for (src, char, tgt) in trns:
if char == '':
self.epsilon_states.add(src)
for state in tgt:
self.trns[src, char].add(state)
def recognize_next_char(self, state, strng, index):
ch = '' if state in self.epsilon_states else strng[index]
if (state, ch) in self.trns.keys():
next_states = self.trns[(state, ch)]
if ch != '':
index += 1
for next_state in next_states:
if index == len(strng):
if next_state in self.final:
return True
elif self.recognize_next_char(next_state, strng, index):
return True
return False
else:
return False
def recognizewords(self, strng):
if len(strng) == 0:
if self.initial in self.final:
return True
if self.initial not in self.epsilon_states:
return false
return self.recognize_next_char(self.initial, strng, 0)
exampleO = NFA(0, [(0,'',(1,5)), (1,'o',(2,)), (2,'k',(3,4)), (3,'i',(2,)), (4,'!',(99,)), (5,'O', (6,)), (6,'K',(99,))], [99])
print(exampleO.recognizewords("okikik!"))
print(exampleO.recognizewords("ok!"))
print(exampleO.recognizewords("OK"))
print(exampleO.recognizewords("ok"))
print(exampleO.recognizewords("oki"))
print(exampleO.recognizewords("okx"))
印刷品:
True
True
True
False
False
False
True
True
True
True
使用ε变换识别ab(cd|ef)gh的示例
这并不是对代码的修复,因为当使用递归而不是显式堆栈时,这类问题的解决方案更容易可视化(至少对我来说)。正如我在评论中提到的,NFA实际上允许在给定的输入字符上转换到多个状态,尤其是空字符串。因此,我修改了输入规范,允许为每个转换指定一个新状态列表。此处,空字符串上的状态0转换为状态1或状态5(可识别OK
)。状态2可在k
上转换为状态3或4
from collections import defaultdict
class NFA:
def __init__(self, initial, trns, final):
self.initial = initial
self.final = set(final)
self.trns = defaultdict(set)
self.epsilon_states = set()
for (src, char, tgt) in trns:
if char == '':
self.epsilon_states.add(src)
for state in tgt:
self.trns[src, char].add(state)
def recognize_next_char(self, state, strng, index):
ch = '' if state in self.epsilon_states else strng[index]
if (state, ch) in self.trns.keys():
next_states = self.trns[(state, ch)]
if ch != '':
index += 1
for next_state in next_states:
if index == len(strng):
if next_state in self.final:
return True
elif self.recognize_next_char(next_state, strng, index):
return True
return False
else:
return False
def recognizewords(self, strng):
if len(strng) == 0:
if self.initial in self.final:
return True
if self.initial not in self.epsilon_states:
return false
return self.recognize_next_char(self.initial, strng, 0)
exampleO = NFA(0, [(0,'',(1,5)), (1,'o',(2,)), (2,'k',(3,4)), (3,'i',(2,)), (4,'!',(99,)), (5,'O', (6,)), (6,'K',(99,))], [99])
print(exampleO.recognizewords("okikik!"))
print(exampleO.recognizewords("ok!"))
print(exampleO.recognizewords("OK"))
print(exampleO.recognizewords("ok"))
print(exampleO.recognizewords("oki"))
print(exampleO.recognizewords("okx"))
印刷品:
True
True
True
False
False
False
True
True
True
True
使用ε变换识别ab(cd|ef)gh的示例
因此,事实证明,非递归解决方案比正确回溯要复杂一些(它需要更多堆栈)。我更改了几个变量名,这对我来说更符合逻辑。下面有两个版本。第二种方法对第一种方法进行了修改,只做了一些细微的更改,以支持空字符串上的转换:
from collections import defaultdict
class NFA:
def __init__(self, initial, trns, final):
self.initial = initial
self.final = set(final)
self.trns = defaultdict(set)
for (src, char, tgt) in trns:
self.trns[src, char].add(tgt)
def recognizewords(self, strng):
strlen = len(strng)
if strlen == 0:
return self.initial in self.final
index = 0
next_states = [self.initial]
next_states_stack = []
index_stack = []
while index < strlen:
current_letter = strng[index]
if next_states:
state = next_states.pop()
if (state, current_letter) in self.trns.keys():
new_next_states = self.trns[(state, current_letter)]
if new_next_states & self.final:
# did we use up all the characters?
return index == strlen - 1
next_states_stack.append(next_states)
index_stack.append(index)
next_states = list(new_next_states)
index += 1
elif next_states_stack:
next_states = next_states_stack.pop()
index = index_stack.pop()
else:
return False
return False
# ab(d|e)
exampleO = NFA(0, [(0,'a',1), (1,'b',2), (1,'b',3), (2,'d',4), (3,'e',4)], [4])
print(exampleO.recognizewords("abd"))
print(exampleO.recognizewords("abe"))
支持空字符串转换的变体
from collections import defaultdict
class NFA_Epsilon:
def __init__(self, initial, trns, final):
self.initial = initial
self.final = set(final)
self.trns = defaultdict(set)
self.epsilon_states = set()
for (src, char, tgt) in trns:
if char == '':
self.epsilon_states.add(src)
self.trns[src, char].add(tgt)
def recognizewords(self, strng):
strlen = len(strng)
if strlen == 0:
return self.initial in self.final
index = 0
next_states = [self.initial]
next_states_stack = []
index_stack = []
while index < strlen:
if next_states:
state = next_states.pop()
current_letter = '' if state in self.epsilon_states else strng[index]
if (state, current_letter) in self.trns.keys():
new_next_states = self.trns[(state, current_letter)]
if new_next_states & self.final:
# did we use up all the characters?
return index == strlen - 1
next_states_stack.append(next_states)
index_stack.append(index)
next_states = list(new_next_states)
if current_letter != '':
index += 1
elif next_states_stack:
next_states = next_states_stack.pop()
index = index_stack.pop()
else:
return False
return False
# ab(cd|ef)gh
example1 = NFA_Epsilon(0, [
(0,'a',1),
(1,'b',2),
(2,'',3),
(2,'',6),
(3,'c',4),
(4,'d',5),
(5,'',9),
(6,'e',7),
(7,'f',8),
(8,'',9),
(9,'g',10),
(10,'h',11)
],[11])
print(example1.recognizewords('abcdgh'))
print(example1.recognizewords('abefgh'))
因此,事实证明,非递归解决方案比正确回溯要复杂一些(它需要更多堆栈)。我更改了几个变量名,这对我来说更符合逻辑。下面有两个版本。第二种方法对第一种方法进行了修改,只做了一些细微的更改,以支持空字符串上的转换:
from collections import defaultdict
class NFA:
def __init__(self, initial, trns, final):
self.initial = initial
self.final = set(final)
self.trns = defaultdict(set)
for (src, char, tgt) in trns:
self.trns[src, char].add(tgt)
def recognizewords(self, strng):
strlen = len(strng)
if strlen == 0:
return self.initial in self.final
index = 0
next_states = [self.initial]
next_states_stack = []
index_stack = []
while index < strlen:
current_letter = strng[index]
if next_states:
state = next_states.pop()
if (state, current_letter) in self.trns.keys():
new_next_states = self.trns[(state, current_letter)]
if new_next_states & self.final:
# did we use up all the characters?
return index == strlen - 1
next_states_stack.append(next_states)
index_stack.append(index)
next_states = list(new_next_states)
index += 1
elif next_states_stack:
next_states = next_states_stack.pop()
index = index_stack.pop()
else:
return False
return False
# ab(d|e)
exampleO = NFA(0, [(0,'a',1), (1,'b',2), (1,'b',3), (2,'d',4), (3,'e',4)], [4])
print(exampleO.recognizewords("abd"))
print(exampleO.recognizewords("abe"))
支持空字符串转换的变体
from collections import defaultdict
class NFA_Epsilon:
def __init__(self, initial, trns, final):
self.initial = initial
self.final = set(final)
self.trns = defaultdict(set)
self.epsilon_states = set()
for (src, char, tgt) in trns:
if char == '':
self.epsilon_states.add(src)
self.trns[src, char].add(tgt)
def recognizewords(self, strng):
strlen = len(strng)
if strlen == 0:
return self.initial in self.final
index = 0
next_states = [self.initial]
next_states_stack = []
index_stack = []
while index < strlen:
if next_states:
state = next_states.pop()
current_letter = '' if state in self.epsilon_states else strng[index]
if (state, current_letter) in self.trns.keys():
new_next_states = self.trns[(state, current_letter)]
if new_next_states & self.final:
# did we use up all the characters?
return index == strlen - 1
next_states_stack.append(next_states)
index_stack.append(index)
next_states = list(new_next_states)
if current_letter != '':
index += 1
elif next_states_stack:
next_states = next_states_stack.pop()
index = index_stack.pop()
else:
return False
return False
# ab(cd|ef)gh
example1 = NFA_Epsilon(0, [
(0,'a',1),
(1,'b',2),
(2,'',3),
(2,'',6),
(3,'c',4),
(4,'d',5),
(5,'',9),
(6,'e',7),
(7,'f',8),
(8,'',9),
(9,'g',10),
(10,'h',11)
],[11])
print(example1.recognizewords('abcdgh'))
print(example1.recognizewords('abefgh'))
你所拥有的更像是DFA。对于NFA,给定的字符(通常是空字符串)可以从一个状态转换为多个状态。哦,不,我很抱歉,我忘了提到,现在,为了简单起见,我限制我的代码一次只使用一个字符。我真的应该提到这一点,所以我的意图是明确的。你有一套“代码>访问/代码>,它似乎没有任何用途,或者我遗漏了什么吗?你还有另一个问题:考虑<代码> NFA(0,[(0,‘a’,1)”,(1,‘b’,2),(1,‘b’,3),(2,‘,’4),(3,‘E’,4)〕,[4)< /代码>。哪个应该识别abd
或abe
。它在abd
上失败,因为您没有针对看到ab
后可能处于的第二种状态测试输入d
,即状态2,因为当您回到循环的顶部时,而strang和agenda:
,strang
现在为空。是的,您是对的;我试图使用访问集来解决这些问题(他忽略了其他可能的状态),但还没有找到解决方案。我在代码中看到,您使用了一个额外的堆栈。我喜欢使用索引而不是循环遍历字符列表的想法。再次非常感谢。我刚开始学习python,从那以后我真的很喜欢递归!哈哈,你拥有的更像是DFA。对于NFA,给定的字符(通常是空字符串)可以从一个状态转换为多个状态。哦,不,我很抱歉,我忘了提到,现在,为了简单起见,我限制我的代码一次只使用一个字符。我真的应该提到这一点,所以我的意图是明确的。你有一套“代码>访问/代码>,它似乎没有任何用途,或者我遗漏了什么吗?你还有另一个问题:考虑<代码> NFA(0,[(0,‘a’,1)”,(1,‘b’,2),(1,‘b’,3),(2,‘,’4),(3,‘E’,4)〕,[4)< /代码>。哪个应该识别abd
或abe
。它在abd
上失败,因为您没有针对看到ab
后可能处于的第二种状态测试输入d
,即状态2,因为当您回到循环的顶部时,而strang和agenda:
,strang
现在为空。是的,您是对的;我试图使用访问集来解决这些问题(他忽略了其他可能的状态),但还没有找到解决方案。我在代码中看到,您使用了一个额外的堆栈。我喜欢使用索引而不是循环遍历字符列表的想法。再次非常感谢。我刚开始学习python,从那以后我真的很喜欢递归!哈哈,非常感谢你试图帮助我。我知道递归很好,但我想在没有它的情况下尝试一下。还有一件事我应该提一下。但你是绝对正确的,我将仔细研究你的代码,希望能够纠正我的代码。谢谢你也许还有,如果你有时间,我真的很困惑为什么我的代码会被删除