我希望在这里加快我的发现过程,因为这是我第一次进入词汇分析的世界。也许这是一条错误的道路。首先,我将描述我的问题:
我有非常大的属性文件(按1000个属性的顺序排列),经过蒸馏后,实际上只有大约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词法分析和标记化听起来是我最好的方法,但这是一个非常简单的形式。这是一个简单的语法,一个简单的替代,我想确保我没有带来一个大锤敲钉子。
我可以创建我自己的lexer和记号器,或者ANTlr是一种可能,但是我不喜欢重新发明轮子,ANTlr听起来有点过火了。
我不熟悉编译器技术,所以最好是正确方向的指针&代码。
注意事项:我可以更改输入格式。
发布于 2010-03-01 22:36:45
在用正则表达式进行词法分析上有一篇关于effbot.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')发布于 2010-03-01 21:22:52
一个简单的DFA可以很好地解决这个问题。你只需要几个州:
${${寻找至少一个构成名称的有效字符}。如果属性文件与顺序无关,则可能需要两个pass处理器来验证每个名称是否正确解析。
当然,您需要编写替换代码,但是一旦您有了所有使用的名称的列表,最简单的实现就是在${name}上找到/替换它的相应值。
发布于 2010-03-01 20:50:03
因为尽管您的格式看起来很简单,但我认为一个完整的解析器/词法器可能会太过分了。看起来,将regexes和字符串操作结合起来就可以做到这一点。
另一个想法是将文件更改为类似于json或xml的内容,并使用现有的包。
https://stackoverflow.com/questions/2358890
复制相似问题