Python解析器层匹配错误的正则表达式
Posted
技术标签:
【中文标题】Python解析器层匹配错误的正则表达式【英文标题】:Python parser ply matches wrong regex 【发布时间】:2017-02-16 20:42:11 【问题描述】:我正在尝试使用 Ply 创建解析器,但遇到了一个奇怪的错误。 这是发生匹配错误的 MCVE:
词法分析器
import ply.lex as lex
tokens = (
'IDENTIFIER',
'NAME',
'EQUALS'
)
def t_IDENTIFIER(t):
r'\* *[a-zA-Z_]+'
print("identifier")
return t
def t_NAME(t):
r"[a-zA-Z_]+"
print("name")
return t
t_EQUALS = r"="
t_ignore = ' \t'
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
# Error handling rule
def t_error(t):
print("Illegal character '%s' at line' %s'" % (t.value[0] , t.lexer.lineno ))
t.lexer.skip(1)
# Build the lexer
lexer = lex.lex()
解析器
import ply.yacc as yacc
from l import tokens
def p_main(p):
'''
main : NAME EQUALS NAME
'''
def p_error(p):
if p is not None:
print ("Line %s, illegal token %s" % (p.lineno, p.value))
else:
print("Syntax error in input!")
parser = yacc.yacc()
with open('simple2','r') as f:
result = parser.parse(f.read())
我的输入文件只包含这个:
A = B
发生的情况是第一个单词A
与标记IDENTIFIER
匹配,即使它不应该这样做,因为正则表达式需要在字母前加上*
。
在此之后,解析器无法识别表达式,因为词法分析器没有返回正确的标记。
怎么了?用于标记 IDENTIFIER 的正则表达式在 Python 中完美运行。
【问题讨论】:
也许\*
被视为 "many \ or none"
?你试过\ A = B
吗?
不,这是匹配*
的正确方式。我尝试了一个单独的规则,例如 `r"*" 并且这个规则正确匹配了星号。
我只是在问
我也试过这个r'^\* *[a-zA-Z_]+
并且还有另一个奇怪的行为,即只有当第一个NAME
标记前面有一个空行(仅\n
)时,输入才被正确解析。
【参考方案1】:
根据PLY manual:(强调添加)
在内部,
lex.py
使用re
模块进行模式匹配。 模式是使用re.VERBOSE
标志编译的,它可以用来提高可读性。但是,请注意,未转义的空格将被忽略,并且在此模式下允许使用 cmets。如果您的模式涉及空格,请确保使用\s
。如果需要匹配#
字符,请使用[#]
。
因此,正则表达式\* *[a-zA-Z_]+
中的空格字符被忽略,从而使正则表达式有效地变为\**[a-zA-Z_]+
;即零个或多个星。如果你真的希望它是一个星号,后面跟着一个或多个空格,你会想要这样的东西:\*\ [a-zA-Z_]+
。
【讨论】:
【参考方案2】:我想我找到了问题和解决方案。
问题是'*'
in ' *'
因为它将'\* '
视为一个字符串 - 所以'\* *'
多次表示'\* '
或none(如'abc*'
表示'abc'
多次或没有)。
您需要'\*[ ]*'
或'\*\s*'
【讨论】:
以上是关于Python解析器层匹配错误的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章