pilot
pilot copied to clipboard
无法理解正则表达式附录的eliza模块中的匹配规则
大致了解并练习了本章节的主要语法与用法,打算尝试理解eliza模块。我的思路,直接从头阅读源代码。
但以下代码,尝试简化并拆分。但还是无法理解。 代码如下:
self.keys = list(
map( lambda x: re.compile(x[0], re.IGNORECASE), gPats))
list函数中嵌套着map函数,其中函数为lambda表达式,参数x
,匹配规则为参数x + 集合原子[0]。re.IGNORECASE我查了一下,这个标志允许正则表达式与给定的字符串进行不区分大小写的匹配。
gPats为可迭代对象,以下是gPats具体的值。
gPats = [r'I need (.*)',
[ "Why do you need %1?",
"Would it really help you to get %1?",
"Are you sure you need %1?"]],
老师这一整个嵌套的列套是一个整体的匹配规则吗? 还是说,在逗号分隔的地方为一个匹配规则。我也尝试把此规则放进regex101,但还是不能理解,希望老师给点线索。
这个问题的关键是你要理解 map()
函数的机制,我简单写下,你可能还需要读读相关的文档:
-
map(f, seq)
接受两个参数,第一个参数是个函数,第二个参数是个列表(其实任何 iterable object 都可以); -
map
函数会按顺序用seq
里的每个元素作为参数去调用函数f
,所以f
必然是一个单参数的函数; - 调用的结果按照原顺序组成一个新的列表,这个列表就是
map
的返回值。
而你的例子里的函数 f
是什么呢?大致长这样:
def f(x):
return re.compile(x[0], re.IGNORECASE)
也就是说,f
的作用是取出列表里的每个元素,然后把这个元素(本身又是个列表)的第一个元素拿出来,编译成一个正则匹配对象,并返回。
再来看要被函数 f
反复操作的 gPats
列表,它的结构是这样的:
gPats = [
[
r'I need (.*)',
[
"Why do you need %1?", "Would it really help you to get %1?",
"Are you sure you need %1?"
]
],
[
r'Why don\'?t you ([^\?]*)\??',
[
"Do you really think I don't %1?", "Perhaps eventually I will %1.",
"Do you really want me to %1?"
]
],
[
r'Why can\'?t I ([^\?]*)\??',
[
"Do you think you should be able to %1?",
"If you could %1, what would you do?",
"I don't know -- why can't you %1?", "Have you really tried?"
]
],
...
]
这个列表的每个元素都是一个小列表,每个小列表里有两个元素,第一个是个正则匹配串,比如 r'I need (.*)'
,所以上面的 map
函数就是把这些正则匹配串取出来组成一个新的列表(保存在 self.keys
中),源代码后面还把 gPats
里每个元素的第二个元素(是个包含若干字符串的列表)取出来,组成了另一个列表(保存在 self.values
中)。
事实上,如果你搞不清楚一些问题,最好的办法是把整个代码放进一个 Jupyter Notebook,分段落执行,看每一步的输出结果,有些问题的答案自己就能猜出来了。
老师,有个疑惑。已经尝试理解,Eliza模块的基本结构与逻辑。为了追求更深入的理解。是否应该尝试理解为什么它要这么写,或者进一步开始模仿吗?
老师,有个疑惑。已经尝试理解,Eliza模块的基本结构与逻辑。为了追求更深入的理解。是否应该尝试理解为什么它要这么写,或者进一步开始模仿吗?
个人认为更好的思路是,要么自己扔开这个实现自己尝试写个出来(之前研究原代码得到的知识可以用),要么尝试改进原代码实现更多功能,后者更容易一些。