ply lexmatch 正则表达式的分组与普通的 re 不同

6 投票
2 回答
1319 浏览
提问于 2025-04-17 02:28

我在使用ply这个库时,发现了一个奇怪的问题:在t.lex.lexmatch中存储的token匹配结果和用re模块定义的sre_pattern相比,似乎有些不对劲。具体来说,group(x)的索引似乎偏差了1。

为了说明我遇到的情况,我定义了一个简单的词法分析器:

import ply.lex as lex

tokens = ('CHAR',)

def t_CHAR(t):
    r'.'
    t.value = t.lexer.lexmatch
    return t

l = lex.lex()

(我收到关于t_error的警告,但暂时不去理会。)现在我给词法分析器输入一些内容,得到一个token:

l.input('hello')
l.token()

我得到了一个LexToken(CHAR,<_sre.SRE_Match object at 0x100fb1eb8>,1,0)。我想看看这个匹配对象:

m = _.value

现在我查看一下组的内容:

m.group() => 'h',这正是我所期待的。

m.group(0) => 'h',这也符合我的预期。

m.group(1) => 'h',但我本来以为不会有这样的组。

把这个和手动创建一个正则表达式进行比较:

import re
p = re.compile(r'.')
m2 = p.match('hello')

这样得到的组就不一样了:

m2.group() = 'h',这也是我所期待的。

m2.group(0) = 'h',这也符合我的预期。

m2.group(1) 返回IndexError: no such group,这也是我所期待的。

有没有人知道为什么会出现这样的差异呢?

2 个回答

1

我觉得匹配的组是依赖于文件中token函数的位置的,就好像这些组实际上是通过所有声明的token正则表达式累积起来的一样:

   t_MYTOKEN1(t):
      r'matchit(\w+)'
      t.value = lexer.lexmatch.group(1)
      return t

   t_MYTOKEN2(t):
      r'matchit(\w+)'
      t.value = lexer.lexmatch.group(2)
      return t
5

在PLY的3.4版本中,这个问题的出现跟表达式是如何从文档字符串转换成模式有关。

查看源代码真的很有帮助 - 在lex.py的第746行:

c = re.compile("(?P<%s>%s)" % (fname,f.__doc__), re.VERBOSE | self.reflags)

我不建议在不同版本之间依赖这样的东西 - 这只是PLY工作原理中的一部分神奇。

撰写回答