ply.lex 是否只解析一次相同的标记?
我在阅读一份关于词法解析的文档,目的是为了能解析一些参数。我完全按照文档的指导创建了一个解析器。这是我的完整代码:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import ply.lex as lex
args = ['[watashi]', '[anata]>500', '[kare]>400&&[kare]<800']
tokens = ('NUMBER', 'EXPRESSION', 'AND', 'LESS', 'MORE')
t_EXPRESSION = r'\[.*\]'
t_AND = r'&&'
t_LESS = r'<'
t_MORE = r'>'
t_ignore = '\t'
def t_NUMBER(t):
r'\d+'
t.value = int(t.value)
return t
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
def t_error(t):
print 'Illegal character "%s"' % t.value[0]
t.lexer.skip(1)
lexer = lex.lex()
for i in args:
lexer.input(i)
while True:
tok = lexer.token()
if not tok: break
print tok
print '#############'
我简单地创建了一个样本参数列表,得到了这个输出:
LexToken(EXPRESSION,'[watashi]',1,0)
#############
LexToken(EXPRESSION,'[anata]',1,0)
LexToken(MORE,'>',1,7)
LexToken(NUMBER,500,1,8)
#############
LexToken(EXPRESSION,'[kare]>400&&[kare]',1,0)
LexToken(LESS,'<',1,18)
LexToken(NUMBER,800,1,19)
#############
前两个样本参数解析得很正确,但第三个却不对。第三个样本参数是 EXPRESSION+LESS+NUMBER,而它应该是 EXPRESSION+MORE+NUMBER+AND+EXPRESSION+LESS+NUMBER。所以我想可能有以下几个问题:
ply.lex 只解析了一个标记:在上面的代码中,ply.lex 不能解析两个独立的表达式,它只返回最新的标记作为类型。"[kare]>400&&[kare]" 被解析为 EXPRESSION,因为它以最新的 EXPRESSION 标记结束,而这个标记是第二个 [kare],而 800 被解析为 NUMBER,因为它是最新的 NUMBER 标记。
!!! 或者 !!!
t_EXPRESSION 变量有错误:我把这个变量定义为 "[.*]",目的是为了获取这两个括号([])中的所有字符。第三个样本参数的第一个标记是 "[kare]>400&&[kare]",因为它简单地以这些括号开始和结束,并且里面包含 .*(每一个字符),但我以为解释器会在第一个(])字符处停止。
所以我找不到解决办法,只好在这里询问。
总的来说,这就是我正在挣扎的内容
lexer.input("[kare]>400&&[kare]<800")
while True:
tok = lexer.token()
if not tok: break
print tok
我得到的结果是
LexToken(EXPRESSION,'[kare]>400&&[kare]',1,0)
LexToken(LESS,'<',1,18)
LexToken(NUMBER,800,1,19)
但我期待的结果更像是
LexToken(EXPRESSION,'[kare]',1.0)
LexToken(LESS,'>',?)
LexToken(NUMBER,400,?)
LexToken(AND,'&&',?)
LexToken(EXPRESSION,'[kare]',1,0)
LexToken(LESS,'<',1,18)
LexToken(NUMBER,800,1,19)
1 个回答
2
我想我明白你的问题了。
t_EXPRESSION = r'\[.*\]'
这个匹配方式是贪婪的,它会尽量匹配到最大的内容,比如说 '[kare]>400&&[kare]'
。
你可以试试下面这个:
t_EXPRESSION = r'\[[^\]]*\]'
这个方法只会匹配一组,因为它寻找的是没有打开的括号的内容([^\]
),而不是任何东西(.
)。
你也可以使用不贪婪的匹配方式。
t_EXPRESSION = r'\[.*?\]'
这里的 ?
会让它尽量匹配最少的字符,而不是最多的。