解析TCL类似文本
我有一段配置文本,内容大概是这样的:
text="""
key1 value1
key2 { value1 value2 }
key3 subkey1 {
key1 1
key2 2
key3 {
value1
}
}
BLOBKEY name {
dont {
# comment
parse { me }
}
}
key3 subkey2 {
key1 value1
}
"""
这些值要么是普通字符串,要么是带引号的字符串。键则是一些字母和数字组合的字符串。我知道在开始的时候,key2
和 key3.subkey1.key4
会包含一组值,所以我可以对待这些路径的方式有所不同。同样,我知道 BLOBKEY
会包含一个“转义”的配置部分。
我的目标是把它转换成一个字典,格式大概是这样的:
{'key1': 'value1',
'key2': set(['value1', 'value2']),
'key3': {
'subkey1': {
'key1': 1,
'key2': 2,
'key3': set(['value1']),
},
'subkey2': {
'key1': 'value1'
}
},
'BLOBKEY': {
'name': " dont {\n # comment\n parse { me }\n }\n"
}
}
下面这段代码在把它拆分成一堆嵌套列表方面做得相当不错。
import pyparsing
string = pyparsing.CharsNotIn("{} \t\r\n")
group = pyparsing.Forward()
group << (
pyparsing.Group(pyparsing.Literal("{").suppress() +
pyparsing.ZeroOrMore(group) +
pyparsing.Literal("}").suppress()) |
string
)
toplevel = pyparsing.OneOrMore(group)
那么,使用 Python 和 pyparsing,最好的方法是什么来得到我想要的结果呢?
1 个回答
3
这是我目前的进展。虽然它还不能处理原始数据块,但其他部分看起来都没问题。
LBRA = Literal("{").suppress()
RBRA = Literal("}").suppress()
EOL = lineEnd.suppress()
tmshString = Word(alphanums + '!#$%&()*+,-./:;<=>?@[\]^_`|~')
tmshValue = Combine( tmshString | dblQuotedString.setParseAction( removeQuotes ))
tmshKey = tmshString
def toSet(s, loc, t):
return set(t[0])
tmshSet = LBRA + Group(ZeroOrMore(tmshValue.setWhitespaceChars(' '))).setParseAction(toSet) + RBRA
def toDict(d, l):
if not l[0] in d:
d[l[0]] = {}
for v in l[1:]:
if type(v) == list:
toDict(d[l[0]],v)
else:
d[l[0]] = v
def trueDefault(s, loc, t):
return len(t) and t or True
singleKeyValue = Forward()
singleKeyValue << (
Group(
tmshKey + (
# A toggle value (i.e. key without value).
EOL.setParseAction(trueDefault) |
# A set of values on a single line.
tmshSet |
# A normal value or another singleKeyValue group.
Optional(tmshValue | LBRA + ZeroOrMore(singleKeyValue) + RBRA).setParseAction(trueDefault)
)
)
)
multiKeysOneValue = Forward()
multiKeysOneValue << (
Group(
tmshKey + (
multiKeysOneValue |
tmshSet |
LBRA + ZeroOrMore(singleKeyValue) + RBRA
)
)
)
toplevel = OneOrMore(multiKeysOneValue)
# now parse data and print results
data = toplevel.parseString(testData)
h = {}
map(lambda x:toDict(h, x), data.asList())
pprint(h)