使用pyparsing将lvm.conf转换为python dict
我正在尝试将lvm.conf转换为python(类似JSON)对象。 LVM(逻辑卷管理)配置文件如下所示:使用pyparsing将lvm.conf转换为python dict,python,pyparsing,lvm,Python,Pyparsing,Lvm,我正在尝试将lvm.conf转换为python(类似JSON)对象。 LVM(逻辑卷管理)配置文件如下所示: # Configuration section config. # How LVM configuration settings are handled. config { # Configuration option config/checks. # If enabled, any LVM configuration mismatch is reported.
# Configuration section config.
# How LVM configuration settings are handled.
config {
# Configuration option config/checks.
# If enabled, any LVM configuration mismatch is reported.
# This implies checking that the configuration key is understood by
# LVM and that the value of the key is the proper type. If disabled,
# any configuration mismatch is ignored and the default value is used
# without any warning (a message about the configuration key not being
# found is issued in verbose mode only).
checks = 1
# Configuration option config/abort_on_errors.
# Abort the LVM process if a configuration mismatch is found.
abort_on_errors = 0
# Configuration option config/profile_dir.
# Directory where LVM looks for configuration profiles.
profile_dir = "/etc/lvm/profile"
}
local {
}
log {
verbose=0
silent=0
syslog=1
overwrite=0
level=0
indent=1
command_names=0
prefix=" "
activation=0
debug_classes=["memory","devices","activation","allocation","lvmetad","metadata","cache","locking","lvmpolld","dbus"]
}
{ "section_name"":
{"value1" : 1,
"value2" : "some_string",
"value3" : [list, of, strings]}... and so on.}
我想得到Python dict,如下所示:
# Configuration section config.
# How LVM configuration settings are handled.
config {
# Configuration option config/checks.
# If enabled, any LVM configuration mismatch is reported.
# This implies checking that the configuration key is understood by
# LVM and that the value of the key is the proper type. If disabled,
# any configuration mismatch is ignored and the default value is used
# without any warning (a message about the configuration key not being
# found is issued in verbose mode only).
checks = 1
# Configuration option config/abort_on_errors.
# Abort the LVM process if a configuration mismatch is found.
abort_on_errors = 0
# Configuration option config/profile_dir.
# Directory where LVM looks for configuration profiles.
profile_dir = "/etc/lvm/profile"
}
local {
}
log {
verbose=0
silent=0
syslog=1
overwrite=0
level=0
indent=1
command_names=0
prefix=" "
activation=0
debug_classes=["memory","devices","activation","allocation","lvmetad","metadata","cache","locking","lvmpolld","dbus"]
}
{ "section_name"":
{"value1" : 1,
"value2" : "some_string",
"value3" : [list, of, strings]}... and so on.}
解析器函数:
def parseLvmConfig2(path="/etc/lvm/lvm.conf"):
try:
EQ, LBRACE, RBRACE, LQ, RQ = map(pp.Suppress, "={}[]")
comment = pp.Suppress("#") + pp.Suppress(pp.restOfLine)
configSection = pp.Word(pp.alphas + "_") + LBRACE
sectionKey = pp.Word(pp.alphas + "_")
sectionValue = pp.Forward()
entry = pp.Group(sectionKey + EQ + sectionValue)
real = pp.Regex(r"[+-]?\d+\.\d*").setParseAction(lambda x: float(x[0]))
integer = pp.Regex(r"[+-]?\d+").setParseAction(lambda x: int(x[0]))
listval = pp.Regex(r'(?:\[)(.*)?(?:\])').setParseAction(lambda x: eval(x[0]))
pp.dblQuotedString.setParseAction(pp.removeQuotes)
struct = pp.Group(pp.ZeroOrMore(entry) + RBRACE)
sectionValue << (pp.dblQuotedString | real | integer | listval)
parser = pp.ZeroOrMore(configSection + pp.Dict(struct))
res = parser.parseFile(path)
print(res)
except (pp.ParseBaseException, ) as e:
print("lvm.conf bad format {0}".format(e))
def parseLvmConfig2(path=“/etc/lvm/lvm.conf”):
尝试:
等式,LBRACE,RBRACE,LQ,RQ=map(pp.Suppress,“={}[]”)
comment=pp.Suppress(“#”)和pp.Suppress(pp.restOfLine)
configSection=pp.Word(pp.alphas+“”)+LBRACE
sectionKey=pp.Word(pp.alphas+“389;”)
sectionValue=pp.Forward()
条目=pp.Group(sectionKey+EQ+sectionValue)
real=pp.Regex(r“[+-]?\d+\.\d*”).setParseAction(lambda x:float(x[0]))
整数=pp.Regex(r“[+-]?\d+”).setParseAction(lambda x:int(x[0]))
listval=pp.Regex(r'(?:\[)(.*)(?:\])).setParseAction(lambda x:eval(x[0]))
pp.dblQuotedString.setParseAction(pp.removeQuotes)
struct=pp.Group(pp.ZeroOrMore(条目)+RBRACE)
sectionValue步骤1应始终至少为您要解析的格式粗略绘制一个BNF。这确实有助于组织您的想法,并让您在开始编写实际代码之前考虑正在解析的结构和数据
下面是我为这个配置提供的一个BNF(它看起来像一个Python字符串,因为这样可以很容易地粘贴到代码中供将来参考-但是pyparsing不使用或需要这样的字符串,它们纯粹是一个设计工具):
请注意,开始和结束{}和[]处于同一级别,而不是在一个表达式中有一个开始符,在另一个表达式中有一个结束符
这个BNF还允许嵌套在structs中的structs,这在您发布的示例文本中不是严格要求的,但是由于您的代码似乎支持这一点,所以我将其包括在内
从这里到pyparsing的转换非常简单,通过BNF自下而上:
EQ, LBRACE, RBRACE, LQ, RQ = map(pp.Suppress, "={}[]")
comment = "#" + pp.restOfLine
integer = ppc.integer #pp.Regex(r"[+-]?\d+").setParseAction(lambda x: int(x[0]))
real = ppc.real #pp.Regex(r"[+-]?\d+\.\d*").setParseAction(lambda x: float(x[0]))
pp.dblQuotedString.setParseAction(pp.removeQuotes)
scalar_value = real | integer | pp.dblQuotedString
# `delimitedList(expr)` is a shortcut for `expr + ZeroOrMore(',' + expr)`
list_value = pp.Group(LQ + pp.delimitedList(scalar_value) + RQ)
key = pp.Word(pp.alphas + "_", pp.alphanums + '_')
key_value = pp.Group(key + EQ + (scalar_value | list_value))
struct = pp.Forward()
entry = key_value | pp.Group(key + struct)
struct <<= (LBRACE + pp.ZeroOrMore(entry) + RBRACE)
parser = pp.ZeroOrMore(entry)
parser.ignore(comment)
提供此嵌套列表:
[['config',
['checks', 1],
['abort_on_errors', 0],
['profile_dir', '/etc/lvm/profile']],
['local'],
['log',
['verbose', 0],
['silent', 0],
['syslog', 1],
['overwrite', 0],
['level', 0],
['indent', 1],
['command_names', 0],
['prefix', ' '],
['activation', 0],
['debug_classes',
['memory',
'devices',
'activation',
'allocation',
'lvmetad',
'metadata',
'cache',
'locking',
'lvmpolld',
'dbus']]]]
我认为您更喜欢的格式是,您可以在嵌套dict或层次对象中以键的形式访问值。Pyparsing有一个名为Dict的类,该类将在解析时执行此操作,以便自动为嵌套的子组分配结果名称。将这两行更改为自动口述其子条目:
struct <<= pp.Dict(LBRACE + pp.ZeroOrMore(entry) + RBRACE)
parser = pp.Dict(pp.ZeroOrMore(entry))
然后,您可以访问字段作为res['config']['checks']
或res.log.indent
您说“如何使pyparsing
执行该工作”-确切地说,执行什么工作?我已经提到了它-作为输出Python dict对象,现在它是解析结果的列表,我不知道如何使用pyparsing将其与dict相结合(如果可能的话?)?
struct <<= pp.Dict(LBRACE + pp.ZeroOrMore(entry) + RBRACE)
parser = pp.Dict(pp.ZeroOrMore(entry))
[['config', ['checks', 1], ['abort_on_errors', 0], ['profile_dir', '/etc/lvm/profile']], ['local'], ['log', ['verbose', 0], ['silent', 0], ['syslog', 1], ['overwrite', 0], ['level', 0], ['indent', 1], ['command_names', 0], ['prefix', ' '], ['activation', 0], ['debug_classes', ['memory', 'devices', 'activation', 'allocation', 'lvmetad', 'metadata', 'cache', 'locking', 'lvmpolld', 'dbus']]]]
- config: [['checks', 1], ['abort_on_errors', 0], ['profile_dir', '/etc/lvm/profile']]
- abort_on_errors: 0
- checks: 1
- profile_dir: '/etc/lvm/profile'
- local: ''
- log: [['verbose', 0], ['silent', 0], ['syslog', 1], ['overwrite', 0], ['level', 0], ['indent', 1], ['command_names', 0], ['prefix', ' '], ['activation', 0], ['debug_classes', ['memory', 'devices', 'activation', 'allocation', 'lvmetad', 'metadata', 'cache', 'locking', 'lvmpolld', 'dbus']]]
- activation: 0
- command_names: 0
- debug_classes: ['memory', 'devices', 'activation', 'allocation', 'lvmetad', 'metadata', 'cache', 'locking', 'lvmpolld', 'dbus']
- indent: 1
- level: 0
- overwrite: 0
- prefix: ' '
- silent: 0
- syslog: 1
- verbose: 0