Python解析器匹配错误的正则表达式

时间:2016-10-07 19:01:47

标签: python regex parsing lexer ply

我正在尝试使用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中完美运行。

2 个答案:

答案 0 :(得分:1)

我想我发现了问题和解决方案。

' *'中的问题是'\* ',因为它将'\* *'视为一个字符串 - 所以'\* '表示'abc*'多次或(例如'abc'表示'\*[ ]*'多次或没有)。

您需要'\*\s*'xhr

答案 1 :(得分:1)

根据PLY manual :(强调添加)

  

在内部,lex.py使用re模块进行模式匹配。 使用re.VERBOSE标志编译模式,可用于帮助提高可读性。但是,请注意忽略未转义的空格并在此模式下允许注释。如果您的模式涉及空格,请确保使用\s。如果您需要匹配#字符,请使用[#]

因此,正则表达式\* *[a-zA-Z_]+中的空格字符将被忽略,从而有效地生成正则表达式\**[a-zA-Z_]+;即零个或多个星星。如果你真的希望它是一个明星,后跟一个或多个空格,你会想要像:\*\ [a-zA-Z_]+