我试图用Python实现NFA来识别单词,但是我的代码不起作用,

2024-06-10 22:34:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试实现一种识别单词的方法。我已经写了下面的代码,并试图按照我的代码在纸上,并执行它一步一步的例子输入,但我找不到原因,为什么我的代码没有做我想让他做的事。有人看到缺陷了吗?我看不见它,我很困惑为什么它不起作用。你知道吗

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号在自我终结,因为自我终结是[3]作为我的对象的例子。。。。你知道吗


Tags: 代码inselfforcurrent例子initialfinal
2条回答

这并不是对代码的修复,因为当您使用递归而不是显式堆栈时,这类问题的解决方案更容易可视化(至少对我来说)。正如我在评论中提到的,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

使用Epsilon变换识别ab(cd|ef)gh

enter image description here

因此,事实证明,非递归解决方案比必须正确执行回溯要复杂一些(它需要更多的堆栈)。我已经更改了一些变量名,这对我来说更符合逻辑。下面有两个版本。第二种方法对第一种方法进行了修改,只是做了一些细微的修改,以支持空字符串上的转换:

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"))

印刷品:

True
True

支持空字符串转换的变体

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'))

印刷品:

True
True

相关问题 更多 >