在python中设计和实现DFA

在python中设计和实现DFA,python,dfa,Python,Dfa,我有一种语言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'},'w

我有一种语言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")
感谢您的帮助!
(请注意,我暂时借用了一个函数,以便理解其中的概念。

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

编辑: 您选择的示例并不理想,因为它有一个相当大的字母表(即所有可能的输入字符),至少
[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基本上由
转换表定义。此转换表将当前状态和当前输入的每个(有效)组合映射到相应的后续状态。这样的表可以建模为字典字典字典。例如:外部dict包含作为键的状态和作为值的字典,这些字典依次具有作为键的有效输入和作为值的后续状态

编辑: 您选择的示例并不理想,因为它有一个相当大的字母表(即所有可能的输入字符),至少
[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 = {0:{'0':0, '1':1},
       1:{'0':2, '1':0},
       2:{'0':1, '1':2}}
如您所见,第一个字典包含数字0、1和2,它们本身就是字典。这些是你们的州。在他们的字典中,dfa将读取一个字符,
'0'
'1'
。对于那些读取的字符,它还提供了下一个状态

例如:

  • 您从状态0开始
  • 你读到了字符“1”
  • 你去第一州
  • 有一个答案可以解释这是如何实现的,但您也会问为什么字典字典可以解释不同的状态。因此,根据上述答案,让我们举一个例子:

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

    例如:

  • 您从状态0开始
  • 你读到了字符“1”
  • 你去第一州

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