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解析器层匹配错误的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

Python正则表达式解析流

python爬虫--解析网页几种方法之正则表达式

从 python 中成功的正则表达式匹配构建字典

Python中正则表达式的使用

Python Xpath的解析,应用

强烈推荐!Python 这个宝藏库 re 正则匹配