假设我在 Python 中定义了一个字符串,如下所示:
my_string = "something{name1, name2, opt1=2, opt2=text}, something_else{name3, opt1=58}"
我想在 Python 中以一种允许我索引语言的不同结构的方式解析该字符串。
例如,输出可能是一个字典parsing_result
,它允许我以结构化的方式索引不同的元素。
例如,以下内容:
parsing_result['names']
将包含字符串的列表
:['name1', 'name2']
而 parsing_result['options']
将包含一个字典,以便:
parsing_result['something']['options']['opt2']
保存字符串"text"
parsing_result['something_else']['options']['opt1']
保存字符串"58"
我的第一个问题是:如何在 Python 中解决这个问题?是否有任何库可以简化此任务?
对于一个工作示例,我不一定对解析我上面定义的确切语法的解决方案感兴趣(尽管那会很棒),但任何接近它的东西都会很棒。
更新
看起来一般正确的解决方案是使用解析器和词法分析器,例如 ply (谢谢@Joran),但文档有点吓人。当语法是轻量级时,是否有更简单的方法来完成这项工作?
我找到了 this thread其中提供了以下正则表达式以围绕外部逗号分隔字符串:
r = re.compile(r'(?:[^,(]|\([^)]*\))+') r.findall(s)
但这是假设分组字符是
()
(而不是{}
)。我正在尝试对此进行调整,但这看起来并不容易。
最佳答案
我强烈推荐 pyparsing :
The pyparsing module is an alternative approach to creating and executing simple grammars, vs. the traditional lex/yacc approach, or the use of regular expressions.
The Python representation of the grammar is quite readable, owing to the self-explanatory class names, and the use of '+', '|' and '^' operator definitions. The parsed results returned from parseString() can be accessed as a nested list, a dictionary, or an object with named attributes.
示例代码(来自 pyparsing 文档的 Hello world):
from pyparsing import Word, alphas
greet = Word( alphas ) + "," + Word( alphas ) + "!" # <-- grammar defined here
hello = "Hello, World!"
print (hello, "->", greet.parseString( hello ))
输出:
Hello, World! -> ['Hello', ',', 'World', '!']
编辑:这是您的示例语言的解决方案:
from pyparsing import *
import json
identifier = Word(alphas + nums + "_")
expression = identifier("lhs") + Suppress("=") + identifier("rhs")
struct_vals = delimitedList(Group(expression | identifier))
structure = Group(identifier + nestedExpr(opener="{", closer="}", content=struct_vals("vals")))
grammar = delimitedList(structure)
my_string = "something{name1, name2, opt1=2, opt2=text}, something_else{name3, opt1=58}"
parse_result = grammar.parseString(my_string)
result_list = parse_result.asList()
def list_to_dict(l):
d = {}
for struct in l:
d[struct[0]] = {}
for ident in struct[1]:
if len(ident) == 2:
d[struct[0]][ident[0]] = ident[1]
elif len(ident) == 1:
d[struct[0]][ident[0]] = None
return d
print json.dumps(list_to_dict(result_list), indent=2)
输出:(以 JSON 格式打印)
{
"something_else": {
"opt1": "58",
"name3": null
},
"something": {
"opt1": "2",
"opt2": "text",
"name2": null,
"name1": null
}
}
使用 pyparsing API作为探索 pyparsing 功能和理解我的解决方案细微差别的指南。我发现掌握这个库的最快方法是尝试使用您自己想到的一些简单语言。
关于python - 在 Python 中解析轻量级语言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17955593/