【问题标题】:Python - lexical analysis and tokenizationPython - 词法分析和标记化
【发布时间】:2011-01-22 11:12:27
【问题描述】:

我希望在这里加快我的发现过程,因为这是我第一次涉足词法分析领域。也许这甚至是错误的道路。首先,我将描述我的问题:

我有非常大的属性文件(大约 1,000 个属性),经过提炼后,实际上只有大约 15 个重要属性,其余的可以生成或很少更改。

所以,例如:

general {
  name = myname
  ip = 127.0.0.1
}

component1 {
   key = value
   foo = bar
}

这是我想要创建的格式类型,用于标记如下内容:

property.${general.name}blah.home.directory = /blah
property.${general.name}.ip = ${general.ip}
property.${component1}.ip = ${general.ip}
property.${component1}.foo = ${component1.foo}

进入

property.mynameblah.home.directory = /blah
property.myname.ip = 127.0.0.1
property.component1.ip = 127.0.0.1
property.component1.foo = bar

词法分析和标记化听起来是我最好的方法,但这是一种非常简单的形式。这是一个简单的语法,一个简单的替换,我想确保我不会带着大锤敲钉子。

我可以创建自己的词法分析器和分词器,或者可以使用 ANTlr,但我不喜欢重新发明轮子,而且 ANTlr 听起来有点矫枉过正。

我不熟悉编译器技术,因此非常感谢您提供正确方向和代码的指针。

注意:我可以更改输入格式。

【问题讨论】:

  • 为什么不使用 JSON 而不是创建自己的解析器??
  • 您的示例翻译似乎有一些错误。如果不是,我看不出为什么在示例的第 3 行中“${component1}.ip”被翻译成“component1”。如果语法是常规的,我可能会用正则表达式删除 ${identifiers} 并将它们替换为在没有字典条目时通过的字典查找。
  • 这里有几个错误,我想我已经纠正了。

标签: python transform lexical-analysis


【解决方案1】:

Using Regular Expressions for Lexical Analysiseffbot.org 上有一篇很棒的文章。

根据您的问题调整分词器:

import re

token_pattern = r"""
(?P<identifier>[a-zA-Z_][a-zA-Z0-9_]*)
|(?P<integer>[0-9]+)
|(?P<dot>\.)
|(?P<open_variable>[$][{])
|(?P<open_curly>[{])
|(?P<close_curly>[}])
|(?P<newline>\n)
|(?P<whitespace>\s+)
|(?P<equals>[=])
|(?P<slash>[/])
"""

token_re = re.compile(token_pattern, re.VERBOSE)

class TokenizerException(Exception): pass

def tokenize(text):
    pos = 0
    while True:
        m = token_re.match(text, pos)
        if not m: break
        pos = m.end()
        tokname = m.lastgroup
        tokvalue = m.group(tokname)
        yield tokname, tokvalue
    if pos != len(text):
        raise TokenizerException('tokenizer stopped at pos %r of %r' % (
            pos, len(text)))

为了测试它,我们这样做:

stuff = r'property.${general.name}.ip = ${general.ip}'
stuff2 = r'''
general {
  name = myname
  ip = 127.0.0.1
}
'''

print ' stuff '.center(60, '=')
for tok in tokenize(stuff):
    print tok

print ' stuff2 '.center(60, '=')
for tok in tokenize(stuff2):
    print tok

为:

========================== stuff ===========================
('identifier', 'property')
('dot', '.')
('open_variable', '${')
('identifier', 'general')
('dot', '.')
('identifier', 'name')
('close_curly', '}')
('dot', '.')
('identifier', 'ip')
('whitespace', ' ')
('equals', '=')
('whitespace', ' ')
('open_variable', '${')
('identifier', 'general')
('dot', '.')
('identifier', 'ip')
('close_curly', '}')
========================== stuff2 ==========================
('newline', '\n')
('identifier', 'general')
('whitespace', ' ')
('open_curly', '{')
('newline', '\n')
('whitespace', '  ')
('identifier', 'name')
('whitespace', ' ')
('equals', '=')
('whitespace', ' ')
('identifier', 'myname')
('newline', '\n')
('whitespace', '  ')
('identifier', 'ip')
('whitespace', ' ')
('equals', '=')
('whitespace', ' ')
('integer', '127')
('dot', '.')
('integer', '0')
('dot', '.')
('integer', '0')
('dot', '.')
('integer', '1')
('newline', '\n')
('close_curly', '}')
('newline', '\n')

【讨论】:

【解决方案2】:

您提供的语法类似于Mako templates engine。我想你可以试试看,它的 API 相当简单。

【讨论】:

    【解决方案3】:

    一个简单的 DFA 可以很好地解决这个问题。您只需要几个状态:

    1. 寻找${
    2. 看到 ${ 正在寻找至少一个构成名称的有效字符
    3. 看到至少一个有效的姓名字符,正在寻找更多姓名字符或}

    如果属性文件与顺序无关,您可能需要一个两遍处理器来验证每个名称是否正确解析。

    当然,您随后需要编写替换代码,但是一旦您获得了所有使用名称的列表,最简单的可能实现是在 ${name} 上查找/替换其对应的值。

    【讨论】:

    • +up DFA/NFA 永远是最好的。
    【解决方案4】:

    尽管你的格式看起来很简单,但我认为一个完整的解析器/词法分析器会有点矫枉过正。似乎正则表达式和字符串操作的组合可以解决问题。

    另一个想法是将文件更改为 json 或 xml 之类的文件并使用现有的包。

    【讨论】:

      【解决方案5】:

      如果您可以更改输入文件的格式,那么您可以对现有格式使用解析器,例如 JSON。

      但是,从您的问题陈述看来,情况并非如此。因此,如果您想创建自定义词法分析器和解析器,请使用 PLY (Python Lex/Yacc)。它易于使用,与 lex/yacc 一样工作。

      这是使用 PLY 构建的计算器的example 的链接。请注意,以t_ 开头的所有内容都是词法分析器规则——定义一个有效的标记——而所有以p_ 开头的内容都是定义语法产生的解析器规则。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-15
        • 1970-01-01
        • 1970-01-01
        • 2012-05-30
        相关资源
        最近更新 更多