模块来解析python中的简单语法

模块来解析python中的简单语法,python,dictionary,Python,Dictionary,我的目标是在Linux下使用Python2.7.6阅读文件/etc/os release,并获得一本字典。 该文件在Ubuntu中如下所示: NAME="Ubuntu" VERSION="14.04.2 LTS, Trusty Tahr" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 14.04.2 LTS" VERSION_ID="14.04" HOME_URL="http://www.ubuntu.com/" SUPPORT_URL="http:/

我的目标是在Linux下使用Python2.7.6阅读文件
/etc/os release
,并获得一本字典。 该文件在Ubuntu中如下所示:

NAME="Ubuntu"
VERSION="14.04.2 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.2 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
我希望最终得到一个类似以下Python代码所创建的字典结果:

{
'NAME': 'Ubuntu',
'VERSION': '14.04.2 LTS, Trusty Tahr',
'ID': 'ubuntu',
'ID_LIKE': 'debian',
'PRETTY_NAME': 'Ubuntu 14.04.2 LTS',
'VERSION_ID': '14.04',
'HOME_URL': 'http://www.ubuntu.com/',
'SUPPORT_URL': 'http://help.ubuntu.com/',
'BUG_REPORT_URL': 'http://bugs.launchpad.net/ubuntu/',
}
我在Python库中找到了几个解析器,但每个解析器都解析了其他更复杂的语法。我在这里找到了一些例子,但都是关于更复杂的语法,并回答了如何编写解析器的问题。我只是在寻找一个已经存在的模块/函数。如果没有,那么,我将只编写自己的代码(因此我不寻找代码示例,除非这是我应该做的)。问题是,我甚至不知道这种语法的名称。虽然我目前的项目是将
/etc/os release
作为一个字典,但我希望将来需要对类似语法的其他数据执行此操作,因此我的搜索重点是语法,而不是该文件

我认为这样简单的事情应该已经存在了


有趣的是,SO的代码示例显示突出显示了它,好像这里的web代码可以解析它,但这不是Python。

只需通过拆分来创建自己的dict:

with open("/etc/os-release") as f:
    d = {}
    for line in f:
        k,v = line.rstrip().split("=")
        d[k] = v
print(d)
如果确实要删除引号,可以使用strip:

with open("/etc/os-release") as f:
    d = {}
    for line in f:
        k,v = line.rstrip().split("=")
        # .strip('"') will remove if there or else do nothing
        d[k] = v.strip('"') 
print(d)


{'VERSION': '14.04.2 LTS, Trusty Tahr', 'NAME': 'Ubuntu', 'HOME_URL': 'http://www.ubuntu.com/', 'ID': 'ubuntu', 'VERSION_ID': '14.04', 'SUPPORT_URL': 'http://help.ubuntu.com/', 'PRETTY_NAME': 'Ubuntu 14.04.2 LTS', 'BUG_REPORT_URL': 'http://bugs.launchpad.net/ubuntu/', 'ID_LIKE': 'debian'}
{'BUG_REPORT_URL': 'http://bugs.launchpad.net/ubuntu/',
 'HOME_URL': 'http://www.ubuntu.com/',
 'ID': 'ubuntu',
 'ID_LIKE': 'debian',
 'NAME': 'Ubuntu',
 'PRETTY_NAME': 'Ubuntu 14.04.2 LTS',
 'SUPPORT_URL': 'http://help.ubuntu.com/',
 'VERSION': '14.04.2 LTS, Trusty Tahr',
 'VERSION_ID': '14.04'}

Padraic Cunningham的答案是完美的,我只是继续回答第二部分(解析可以存在或不存在的引号):如果您想去掉所有引号,只需在Padraic的代码中添加两行即可

with open("/etc/os-release") as f:
    d = {}
    for line in f:
        k,v = line.rstrip().split("=")
        if v.startswith('"'):
          v = v[1:-1]
        d[k] = v
print(d)
这是因为我们可以假设,如果属性以双引号开始,它将以相同的方式结束。如果您希望单引号也具有相同的行为,只需在If中添加第二个条件

根据:

如果变量赋值值包含空格、分号或A-Z、A-Z、0-9之外的其他特殊字符,则必须用双引号或单引号括起来。Shell特殊字符(“$”、引号、反斜杠、反勾号)必须使用反斜杠转义,并遵循Shell样式。以“#”开头的行应作为注释忽略

在为文件编写解析器时,必须考虑上面引号中指定的每个规则。它很复杂,因为它被设计为作为shell脚本执行。实现这意味着实现shell的一部分


至于引号,它们除了包含复杂的字符串外没有其他意义,因此可以忽略。另一件事你必须考虑的是,由'= '分裂不是100%正确,因为在一行中可能有不止一个'= '。而是按第一个“=”的位置分开。

它也可以用现代(3.5+)python实现为简单的dict理解:

这会生成一个这样的字典

{'name': 'Ubuntu',
 'version': '18.04.2 LTS (Bionic Beaver)',
 'id': 'ubuntu',
 'id_like': 'debian',
 'pretty_name': 'Ubuntu 18.04.2 LTS',
 'version_id': '18.04',
 'home_url': 'https://www.ubuntu.com/',
 'support_url': 'https://help.ubuntu.com/',
 'bug_report_url': 'https://bugs.launchpad.net/ubuntu/',
 'privacy_policy_url': 'https://www.ubuntu.com/legal/terms-and-policies/privacy-policy',
 'version_codename': 'bionic',
 'ubuntu_codename': 'bionic'}
或者,我发现namedtuple非常有用:

from collections import namedtuple
with open('/etc/os-release') as f:
    keys, values = zip(*[
        (k.lower(), v.strip('\'"'))
        for (k, v) in (
            line.strip().split('=', 1) for line in f.read().strip().split('\n')
        )]
    ) 
r = namedtuple("OSRelease", keys)(*values)
这将生成一个namedtuple,其中所有变量都可以作为属性访问:

[ins] In [1]: from collections import namedtuple 
         ...: with open('/etc/os-release') as f: 
         ...:     keys, values = zip(*[ 
         ...:         (k.lower(), v.strip('\'"')) 
         ...:         for (k, v) in ( 
         ...:             line.strip().split('=', 1) for line in f.read().strip().split('\n') 
         ...:         )] 
         ...:     )  
         ...: r = namedtuple("OSRelease", keys)(*values)                                               

[ins] In [2]: print(r)                                                                                 
OSRelease(name='Ubuntu', version='18.04.2 LTS (Bionic Beaver)', id='ubuntu', id_like='debian', pretty_name='Ubuntu 18.04.2 LTS', version_id='18.04', home_url='https://www.ubuntu.com/', support_url='https://help.ubuntu.com/', bug_report_url='https://bugs.launchpad.net/ubuntu/', privacy_policy_url='https://www.ubuntu.com/legal/terms-and-policies/privacy-policy', version_codename='bionic', ubuntu_codename='bionic')

[ins] In [3]: print(r.id)                                                                              
ubuntu

[ins] In [4]: print(r.id_like)                                                                         
debian

[ins] In [5]: print(r.version_id)                                                                      
18.04

[ins] In [6]: print(r.ubuntu_codename)                                                                 
bionic


但这不符合规程,规程是不需要的。。。目标是一个字典这将如何解析可能存在或可能不存在的引号?@Skaperen,你所说的解析可能存在或可能不存在的引号是什么意思?添加
maxslit=1
将防止字符串包含
=
符号时出现问题。
maxslit=1
应处理值中的
=/code>。我不指望他们的名字。
[ins] In [1]: from collections import namedtuple 
         ...: with open('/etc/os-release') as f: 
         ...:     keys, values = zip(*[ 
         ...:         (k.lower(), v.strip('\'"')) 
         ...:         for (k, v) in ( 
         ...:             line.strip().split('=', 1) for line in f.read().strip().split('\n') 
         ...:         )] 
         ...:     )  
         ...: r = namedtuple("OSRelease", keys)(*values)                                               

[ins] In [2]: print(r)                                                                                 
OSRelease(name='Ubuntu', version='18.04.2 LTS (Bionic Beaver)', id='ubuntu', id_like='debian', pretty_name='Ubuntu 18.04.2 LTS', version_id='18.04', home_url='https://www.ubuntu.com/', support_url='https://help.ubuntu.com/', bug_report_url='https://bugs.launchpad.net/ubuntu/', privacy_policy_url='https://www.ubuntu.com/legal/terms-and-policies/privacy-policy', version_codename='bionic', ubuntu_codename='bionic')

[ins] In [3]: print(r.id)                                                                              
ubuntu

[ins] In [4]: print(r.id_like)                                                                         
debian

[ins] In [5]: print(r.version_id)                                                                      
18.04

[ins] In [6]: print(r.ubuntu_codename)                                                                 
bionic