2012-02-07 74 views
0

我正在Python中制作一个简单的聊天机器人。它有一个带有正则表达式的文本文件,可以帮助生成输出。用户输入和机器人输出之间用|字符分隔。如何保存正则表达式的用户输入值(Python)

my name is (?P<'name'>\w*) | Hi {'name'}! 

这工作正常单套的输入和输出响应,但是我希望机器人能够存储正则表达式值的用户输入,然后再次使用它们(即给机器人一个“记忆” )。例如,我想有机器人商店“名”的输入值,这样我可以有这样的规则:

my name is (?P<'word'>\w*) | You said your name is {'name'} already! 
my name is (?P<'name'>\w*) | Hi {'name'}! 

具有“名”呢,机器人会先输出没有价值'嗨史蒂夫',一旦机器人有这个价值,'单词'的规则将适用。鉴于我的程序结构,我不确定这是否可行。我已经这样做了,使得文本文件被制成一个字典,其中键和值由|隔开字符,当用户输入一些文本时,程序将比较用户输入是否与存储在字典中的输入相匹配,并打印出相应的机器人响应(如果未找到匹配,则还有'else'情况)。

我必须在进程的比较部分发生一些事情,以便保存用户的正则表达式文本,然后以某种方式将其替换回字典中。我所有的正则表达式都有不同的名称(没有两个“单词”实例,例如......有“单词”,“单词2”等),我这样做是因为我认为它会使这个过程的一部分更容易。尽管如此,我可能已经完全错误地完成了这个任务。

编辑:代码

import re 

io = {} 

with open("rules.txt") as brain: 
    for line in brain: 
     key, value = line.split('|') 
     io[key] = value 

string = str(raw_input('> ')).lower()+' word' 

x = 1 

while x == 1: 
    for regex, output in io.items(): 
     match = re.match(regex, string) 
     if match: 
      print(output.format(**match.groupdict())) 
      string = str(raw_input('> ')).lower()+' word' 
    else: 
     print ' Sorry?' 
     string = str(raw_input('> ')).lower()+' word' 
+1

- Linus Torvalds。另请参阅[常见问题](http://stackoverflow.com/faq)。 – PointedEars 2012-02-07 10:12:52

+0

@ user1189336在定义名称_string_的对象的表达式中,'word'**的用途是什么? – eyquem 2012-02-07 11:56:10

+0

@eyquem这样做的目的是修复一个错误,即如果用户在输入结束时没有再输入另一个单词,程序将默认为'else'选项。不过,我现在认识到最好简单地将行分割为'|'而不是'|',因为这也能解决我认为的问题。 (是的,工程,derp) – user1189336 2012-02-07 14:04:37

回答

0

我很难理解你的算法的原理,因为我不习惯使用指定的组。
下面的代码是我会解决你的问题的方式,我希望它会给你一些想法。

我认为只有一个字典不是一个好原则,它增加了推理和算法的复杂性。因此,我将代码基于两个字典:direg和内存

这两个字典的键是索引的组,而不是所有的索引,只有一些特定的索引,组的索引是每个单独模式中的最后一个。
因为,为了好玩,我决定正则表达式必须能够有几个组。

我称之为个人模式在我的代码是以下字符串:

"[mM]y name [Ii][sS] (\w*)" 

"[Ii]n repertory (\w*) I [wW][aA][nN][tT] file (\w*)" 

"[Ii] [wW][aA][nN][tT] to ([ \w]*)" 

您将看到第二个人模式有2个捕获组:因此有3种个人模式,但在总共4组所有的个人群体。

所以字典的创建需要一些额外的照顾考虑到一个事实,即最后一个匹配组的索引(我用的名字的属性的帮助下使用lastIndex的正则表达式MatchObject的)可能不对应到正则表达式中存在的单个正则表达式的编号:解释比理解更难。这就是为什么我计算函数distr()字符串{0} {1} {2} {3} {4}等的发生次数等其编号必须与在相应的个人模式。

我找到了Laurence D'Oliveiro建议使用'||'而不是'|'作为分隔符有趣。

我的代码模拟在几个输入端完成会话: “Talk是便宜给我的代码。”

import re 

regi = ("[mM]y name [Ii][sS] (\w*)" 
     "||Hi {0}!" 
     "||You said that your name was {0} !!!", 

     "[Ii]n repertory (\w*) I [wW][aA][nN][tT] file (\w*)" 
     "||OK here's your file {0}\\{1} :" 
     "||I already gave you the file {0}\\{1} !", 

     "[Ii] [wW][aA][nN][tT] to ([ \w]*)" 
     "||OK, I will do {0}" 
     "||You already did {0}. Do yo really want again ?") 


direg = {} 
memory = {} 
def distr(regi,cnt = 0,di = direg,mem = memory, 
      regnb = re.compile('{\d+}')): 
    for i,el in enumerate(regi,start=1): 
     sp = el.split('||') 
     cnt += len(regnb.findall(sp[1])) 
     di[cnt] = sp[1] 
     mem[cnt] = sp[2] 
     yield sp[0] 

regx = re.compile('|'.join(distr(regi))) 
print 'direg :\n',direg 
print 
print 'memory :\n',memory 
for inp in ('I say that my name is Armano the 1st', 
      'In repertory ONE I want file SPACE', 
      'I want to record music', 
      'In repertory ONE I want file SPACE', 
      'I say that my name is Armstrong', 
      'But my name IS Armstrong now !!!', 
      'In repertory TWO I want file EARTH', 
      'Now my name is Helena'): 

    print '\ninput ==',inp 

    mat = regx.search(inp) 
    if direg[mat.lastindex]: 
     print 'output ==',direg[mat.lastindex]\ 
       .format(*(d for d in mat.groups() if d)) 
     direg[mat.lastindex] = None 
     memory[mat.lastindex] = memory[mat.lastindex]\ 
           .format(*(d for d in mat.groups() if d)) 
    else: 
     print 'output ==',memory[mat.lastindex]\ 
       .format(*(d for d in mat.groups() if d)) 
     if not memory[mat.lastindex].startswith('Sorry'): 
      memory[mat.lastindex] = 'Sorry, ' \ 
            + memory[mat.lastindex][0].lower()\ 
            + memory[mat.lastindex][1:] 

结果

direg : 
{1: 'Hi {0}!', 3: "OK here's your file {0}\\{1} :", 4: 'OK, I will do {0}'} 

memory : 
{1: 'You said that your name was {0} !!!', 3: 'I already gave you the file {0}\\{1} !', 4: 'You already did {0}. Do yo really want again ?'} 

input == I say that my name is Armano the 1st 
output == Hi Armano! 

input == In repertory ONE I want file SPACE 
output == OK here's your file ONE\SPACE : 

input == I want to record music 
output == OK, I will do record music 

input == In repertory ONE I want file SPACE 
output == I already gave you the file ONE\SPACE ! 

input == I say that my name is Armstrong 
output == You said that your name was Armano !!! 

input == But my name IS Armstrong now !!! 
output == Sorry, you said that your name was Armano !!! 

input == In repertory TWO I want file EARTH 
output == Sorry, i already gave you the file ONE\SPACE ! 

input == Now my name is Helena 
output == Sorry, you said that your name was Armano !!! 
+0

非常感谢您发布此信息。我仍然阅读并试图理解它,我不是很有经验:) – user1189336 2012-02-07 14:19:58

0

OK,让我看看,如果我理解这一点:

  • 你想键值对的字典。这将是chatbot的“记忆”。
  • 您想要将正则表达式规则应用于用户输入。但是,可能适用的规则取决于内存字典中已经存在哪些键:如果“名称”尚未定义,则应用定义“名称”的规则;但如果是的话,则适用提及“单词”的规则。

对我来说,你需要更多的信息附加到你的规则。例如,上面给出的“单词”规则实际上不应该将“单词”添加到字典中,否则它只会应用一次(想象如果用户不断尝试说“我的名字是x”超过两次)。

这会给你一些关于如何进行的更多想法吗?

哦,顺便说一句,我认为“|”是分隔符的糟糕选择,因为它可能出现在正则表达式中。不知道该怎么建议:“||”怎么样?

+0

感谢您的意见:) 不幸的是,它没有帮助尽可能多,因为我从理论上理解该程序应该做什么,不应该做什么,应该保存而不是保存,但我缺乏实践知识来实现​​它。我认为这个项目实际上对我来说有点雄心勃勃,但是在我的空闲时间里,所以我觉得没问题。 – user1189336 2012-02-07 14:22:36