【问题标题】:designing and implementing a DFA in python [closed]在 python 中设计和实现 DFA [关闭]
【发布时间】:2017-06-30 19:06:30
【问题描述】:

我有一种语言 L,它仅由作为 URL 的字符串组成,我需要设计和实现一个识别 L 的 DFA(例如:www.test.com)。我现在的问题是,一旦您阅读了直到“www.”的所有内容,您怎么知道何时停止阅读“.com”?

到目前为止我的代码:

s = input("Would you like to input a string? y/n")
if(s == 'n'):
    exit
dfa = {'':{'w':'ww'}, 'w': {'w': 'ww'}, 'ww': {'w': 'www'},'www': {'.': 'www.'},"}}
def accepts(transitions,initial,accepting,s):
    state = initial
    for c in s:
        state = transitions[state][c]
    return state in accepting
accepts(dfa,0,{0},"www.hi.com")

感谢任何帮助! (请注意,我暂时从 here 借用了一个函数,以便理解其中的概念。

【问题讨论】:

  • Searching Google for "DFA in Python" 立即提供了几个示例(包括one on Stack Overflow)。他们怎么了?
  • 我通过您链接的堆栈溢出更好地理解了这个概念(不知道为什么我以前找不到它),但是将它应用于整数而不是字符让我感到困惑。

标签: python dfa


【解决方案1】:

DFA 基本上由transition table 定义。此转换表将当前状态和当前输入的每个(有效)组合映射到相应的后继状态。这样的表可以建模为字典的字典。例如:外部字典包含状态作为键和字典作为值,这些字典依次将有效输入作为键和后继状态作为值。

编辑: 您选择的示例并不理想,因为它具有至少[a-zA-Z0-9] 的相当大的字母表(即所有可能的输入字符),链接的答案仅限于[01] 是有原因的;-) 无论如何,我将如何开始:

{
# in state '' we have not yet processed/consumed any input
# it is the start state
# the only valid input is a 'w'
'': {'w': 'w'},    

# in state 'w' we a have already consumed a 'w'
# the only valid input is another 'w'   
'w': {'w': 'ww'},

# in state 'ww' we have previously consumed 'ww'
# the only valid input is still only a 'w'  
'ww': {'w': 'www'},

# now the only valid input is a '.'
'www': {'.': 'www.'},

# this is where your example becomes unpractical:
# we have to add a transition for every valid input
# (you could get around this by using a defaultdict and some kind of special signal value, but im not quite sure you are up to that)
'www.': {'a': 'www.*', 'b': 'www.*', ...},

# I used the star in this state name to symbolize multiple (at least one) valid character
# we only leave this state if we encounter a '.' 
'www.*': {'.': 'www.*.', 'a': 'www.*', 'b': 'www.*', ...},

# it should be obvious how to continue from here 
'www.*.': ...
}

EDIT2:聊天后的实施。

from collections import defaultdict

dfa =  {
  'initial': defaultdict(lambda: 'invalid', w='w'),
  'w': defaultdict(lambda: 'invalid', w='ww'),
  'ww': defaultdict(lambda: 'invalid', w='www'),
  'www': defaultdict(lambda: 'invalid', [('.','www.')]),
  'www.': defaultdict(lambda: 'www.*', [('.','invalid')]),
  'www.*': defaultdict(lambda: 'www.*', [('.','www.*.')]),
  'www.*.': defaultdict(lambda: 'www.*', [('c','www.*.c')]),
  'www.*.c': defaultdict(lambda: 'www.*', [('o','www.*.co')]),
  'www.*.co': defaultdict(lambda: 'www.*', [('m','www.*.com'), ('.','www.*.')]),
  'www.*.com': defaultdict(lambda: 'www.*', [('.','www.*.')]),
  'invalid': defaultdict(lambda: 'invalid')
}
def accepts(transitions,initial,accepting,s):
    state = initial
    for c in s:
        state = transitions[state][c]
        print(c, '->', state)
    return state in accepting
print(accepts(dfa,'initial',{'www.*.com', 'www.*.co'},"www.hi.com"))

【讨论】:

  • 但这与检查字符串是否是语言的一部分有什么关系?
  • 赋值指定 DFA 应该明智地处理字符串字符,因此每个字符都是一个输入,并且状态代表之前使用的输入,这样有效的单词(即 L 中的单词)可以通过为 DFA 选择有效的结束状态来标记。其他人链接到的stackoverflow上的解决方案非常好。您只需要将字母表扩展到 0 和 1 以上。
  • @subzira 不完全是,您按字符处理输入,这是正确的,但这意味着在您的转换表中,您还必须只处理单个字符输入。除了该建议外,还为各州提供更多有用/说话的名称,而不是简单地给它们编号,让它们象征它们所代表的东西。我将使用可能的转换表的开头来更新我的答案。
  • @subzira 您可以通过添加到状态“www.*”的转换来实现它。对于任何不是“c”且只有“c”继续到“www.*.c”的输入,它会(返回)状态“www.*”。您还必须为接下来的两个输入“o”和“m”添加该逻辑。
  • 这似乎是避免添加大量内部字典来处理任何 int 大写或小写字母输入的好方法,但是您如何让 DFA 为除 1 个字符之外的任何内容做一些事情呢?。
【解决方案2】:

有一个答案here 解释了这是如何实现的,但你也问为什么字典字典可以解释不同的状态。因此,从上面提到的答案让我们举个例子:

dfa = {0:{'0':0, '1':1},
       1:{'0':2, '1':0},
       2:{'0':1, '1':2}}

如您所见,第一个字典包含数字 0、1 和 2,它们本身就是字典。这些是您的状态。在他们的字典中有一个你的 dfa 会读到的字符,'0''1'。对于那些读取的字符,它还会为您提供下一个状态。

例如:

  1. 您从状态 0 开始
  2. 你读到了字符“1”
  3. 你进入状态 1

【讨论】:

    猜你喜欢
    • 2018-04-26
    • 2019-10-16
    • 2021-02-13
    • 2011-04-30
    • 1970-01-01
    • 2011-04-29
    • 2014-04-12
    • 1970-01-01
    • 2010-10-11
    相关资源
    最近更新 更多