如何在Python中使用正则表达式与占位符文本?

5
我将翻译如下:

我正在使用Python进行项目开发,需要用户输入文本。如果文本符合程序支持的格式,则会输出包含用户关键字的响应(这是一个简单的聊天机器人)。该格式以用户输入格式和答案格式的形式存储在文本文件中。

例如,文本文件的左侧为用户输入,右侧为输出:

my name is <-name> | Hi there, <-name>

如果用户输入 my name is johnny,我希望程序能够知道 johnny<-name> 变量,并输出响应 Hi there, johnny

能够给我一些指导吗?我以前从未使用过正则表达式,我读过一篇关于如何使用它们的文章,但不幸的是它主要介绍了如何匹配特定单词,对我并没有太大帮助。


我不太确定你在这里问什么。REGEXP 是关于匹配特定的字符串结构(比如单词),还有什么其他的问题吗?任何形式的语义分析都是完全不同的事情。 - hasienda
4个回答

9

这里有一个例子:

import re

io = [
    ('my name is (?P<name>\w+)', 'Hi there, {name}'),
]

string = input('> ')
for regex, output in io:
    match = re.match(regex, string)
    if match:
        print(output.format(**match.groupdict()))
        break

我来带你一起看:
'my name is (?P<name>\w+)'

(?P<name>...) 会将后面的部分 (\w+) 存储在匹配对象中,我们稍后会使用到,存储时会用指定的名称 name 进行标识。


match = re.match(regex, string)

这个函数在给定的输入中查找regex。请注意,re.match只匹配输入的开头,如果您不想受此限制,请改用re.search


如果匹配成功:

output.format(**match.groupdict())

`match.groupdict` 返回一个由 `(?P...)` 定义的键和它们对应的匹配值组成的字典。`**` 将这些键/值传递给 `.format`,在此情况下,Python 将其转换为 `output.format(name='matchedname')`。
要从文件中构建 `io` 字典,请执行以下操作:
io = []
with open('input.txt') as file_:
    for line in file:
        key, value = line.rsplit(' | ', 1)
        io.append(tuple(key, value))

+1,我喜欢这个。它干净而优雅。虽然它并没有真正解决文件输入的问题。 - Niklas B.
3
抱歉,我不认为像这样滥用 re.sub 是必要或明智的。这是模式匹配,然后创建字符串,而不是文本替换。对我来说,这应该是被接受的答案。 - Niklas B.
@hughdbrown,是的,你说得没错。我这么做不太符合Python风格,我会立即修正它的。感谢你指出来。 - Rob Wouters
感谢大家的帮助!我已经尝试了这段代码,发现当添加'else'语句时它不起作用(通常情况下会执行else语句),并且在需要替换文本的情况下也不起作用(仅适用于用户文本与文本文件中的用户文本完全匹配的响应)。 我打印了io字典,发现它看起来与文本文件相同,因此我认为需要对<w1>等进行一些替换以使它们成为正则表达式。也许..? - user1189336
@user1189336,我不知道你在else子句中想要做什么。如果你想回复一个用户说“foo”,并用“bar”作为回复,只需将foo | bar添加到你的文件中即可。 - Rob Wouters
显示剩余8条评论

6
您需要进行组匹配,然后提取搜索组。
首先你需要导入 re 模块, re 是 Python 的正则表达式模块。假设 user_input 是保存输入字符串的变量。然后,您需要使用 re.sub 方法来匹配您的字符串并将其替换为其他内容。 output = re.sub(input_regex, output_regex, user_input) 因此,正则表达式中,首先可以放置您想要的绝对内容: input_regex = '我的名字是' 如果你希望它从行首明确地匹配,那么应该在其前面加上 '^': input_regex = '^我的名字是' 然后,您需要一个组来匹配任何字符串 .+ (. 表示任何字符,+ 表示前面的项有 1 个或多个)直到行尾 '$'。 input_regex = '^我的名字是 .+$' 现在,您将想把它放入命名组中。命名组采用形式 "(?Pregex)" - 请注意,这些尖括号是文字意义的。 input_regex = '^我的名字是 (?P<name> .+)$' 现在,您已经有了一个可以匹配并给出名为 "name" 的匹配组的正则表达式,其中包含用户名称。输出字符串将需要使用 "\g" 引用匹配组。 output_regex = '你好,\g<name>' 将所有这些放在一起,您可以使用单行代码(和导入)来完成这个操作。
import re
output = re.sub('^my name is (?P<name>.+)$', 'Hi there, \g<name>', user_input)

1

询问正则表达式必然会得到像现在这样的答案:基本正则表达式操作的演示:如何拆分句子,在其中搜索一些词组如“my” + “name” + “is”等。

事实上,你可以通过阅读现有的文档和开源程序来学习所有这些。正则表达式并不是很容易理解。但是,如果你想改变和扩展你的程序,仍然需要自己理解一些内容。不要只是从这里复制代码。

但你可能想要更全面的东西。因为你提到要构建一个“聊天机器人”,所以你可能想看看其他人是如何完成这个任务的 - 不仅仅是正则表达式。请看:

所以,如果用户写了“my name is johnny”,我希望程序知道“johnny”是“<-name>”变量,...

根据你的问题还不清楚这个程序应该变得多么复杂。如果他输入了什么呢?

'Johnny is my name.'

或者

'Hey, my name is John X., but call me johnny.'

?


0

看一下re模块,并注意捕获组。

例如,您可以假设名称将是一个单词,因此它匹配\w+。然后,您必须使用\w+捕获组构造正则表达式,其中应该是名称(捕获组由括号分隔):

r'my name is (\w+)'

然后将其与输入进行匹配(提示:在re模块文档中查找match)。

一旦匹配成功,您必须获取捕获组的内容(在此情况下为索引1,索引0保留用于整个匹配),并使用它来构造您的响应。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接