【问题标题】:Lex strings with single, double, or triple quotes带有单引号、双引号或三引号的 Lex 字符串
【发布时间】:2013-12-12 12:08:31
【问题描述】:

我的目标是像 Python 那样解析字符串。

问题:如何编写一个 lex 来支持以下内容:

  1. "string..."
  2. 'string...'
  3. """multi line string \n \n end"""
  4. '''multi line string \n \n end'''

一些代码:

状态 = ( ('字符串','排他'), ) # 字符串 def t_begin_string(self, t): r'(\'|(\'{3})|\"|(\"{3}))' t.lexer.push_state('字符串') def t_string_end(self, t): r'(\'|(\'{3})|\"|(\"{3}))' t.lexer.pop_state() def t_string_newline(self, t): r'\n' t.lexer.lineno += 1 def t_string_error(self, t): print("字符串 '%s' 中有非法字符" % t.value[0]) t.lexer.skip(1)

我目前的想法是创建 4 个唯一状态,以匹配 4 种不同的字符串情况,但我想知道是否有更好的方法。

感谢您的帮助!

【问题讨论】:

  • 您有 4 种不同的字符串类型,所以我希望您需要 4 种不同的状态。大概'string" 格式不正确?
  • 您可以使用两种唯一状态,一种用于单引号,一种用于三引号,但您需要将引号字符存储在某处。哪种方法更好值得商榷。
  • 我担心建立 4 个州...两个可以通过吗?因为开始/结束状态与初始开始报价类型不匹配。例如 "string..'...string..." 解析器会将 string.. 视为字符串,然后将 ...string..." 视为解析错误。
  • 如果你只使用了两个状态,你需要存储你开始的引号,然后如果你遇到一个引号你检查它是否是开始标记,如果不是,继续在相同的状态.

标签: python yacc lexer ply


【解决方案1】:

隔离公共字符串以创建单个状态并尝试构建具有较少状态的自动机但是如果您不担心使用使您的工作更轻松的外部库,您可以查看 py lex yacc

但是你需要 lex yacc 的基础知识 ///示例代码如图所示

tokens = (
    'NAME','NUMBER',
    'PLUS','MINUS','TIMES','DIVIDE','EQUALS',
    'LPAREN','RPAREN',
    )
    enter code here

# Tokens

t_PLUS    = r'\+'
t_MINUS   = r'-'
t_TIMES   = r'\*'
t_DIVIDE  = r'/'
t_EQUALS  = r'='
t_LPAREN  = r'\('
t_RPAREN  = r'\)'
t_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'

def t_NUMBER(t):
    r'\d+'
    try:
        t.value = int(t.value)
    except ValueError:
        print("Integer value too large %d", t.value)
        t.value = 0
    return t

# Ignored characters
t_ignore = " \t"

def t_newline(t):
    r'\n+'
    t.lexer.lineno += t.value.count("\n")

def t_error(t):
    print("Illegal character '%s'" % t.value[0])
    t.lexer.skip(1)

# Build the lexer
import ply.lex as lex
lex.lex()

# Parsing rules

precedence = (
    ('left','PLUS','MINUS'),
    ('left','TIMES','DIVIDE'),
    ('right','UMINUS'),
    )

# dictionary of names
names = { }

def p_statement_assign(t):
    'statement : NAME EQUALS expression'
    names[t[1]] = t[3]

def p_statement_expr(t):
    'statement : expression'
    print(t[1])

def p_expression_binop(t):
    '''expression : expression PLUS expression
                  | expression MINUS expression
                  | expression TIMES expression
                  | expression DIVIDE expression'''
    if t[2] == '+'  : t[0] = t[1] + t[3]
    elif t[2] == '-': t[0] = t[1] - t[3]
    elif t[2] == '*': t[0] = t[1] * t[3]
    elif t[2] == '/': t[0] = t[1] / t[3]

def p_expression_uminus(t):
    'expression : MINUS expression %prec UMINUS'
    t[0] = -t[2]

def p_expression_group(t):
    'expression : LPAREN expression RPAREN'
    t[0] = t[2]

def p_expression_number(t):
    'expression : NUMBER'
    t[0] = t[1]

def p_expression_name(t):
    'expression : NAME'
    try:
        t[0] = names[t[1]]
    except LookupError:
        print("Undefined name '%s'" % t[1])
        t[0] = 0

def p_error(t):
    print("Syntax error at '%s'" % t.value)

import ply.yacc as yacc
yacc.yacc()

while 1:
    try:
        s = input('calc > ')   # Use raw_input on Python 2
    except EOFError:
        break
    yacc.parse(s)

【讨论】:

    【解决方案2】:

    尝试使用pyparsing module。使用此模块,您可以轻松解析具有良好样式的字符串,而无需使用正则表达式。

    下面的例子应该可以帮助你解析像"string...""""string"""这样的表达式。

    from pyparsing import Word, OneOrMore, alphas
    
    string = """string"""
    w = OneOrMore('\"') + Word(alphas + '.') + OneOrMore('\"')
    w.parseString(string)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-26
      • 2015-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      相关资源
      最近更新 更多