8

我已经在这里搜索了一段时间的答案并没有找到它,所以希望这不是一个骗局。

我有一个属性文件,其中主要包含键=值对,但也包含#comments。我需要把它放在字典里,这样我就可以随意获取值了。在没有#comments 的文件中,以下内容完美运行。

myprops = dict(line.strip().split('=') for line in open('/Path/filename.properties'))
print myprops['key']

但当有评论存在时,情况并非如此。如果有#comment,字典说

"ValueError: dictionary update sequence element #x has length 1, 2 is required"

我试过用条件包装字典创建

if not line.startswith('#'):

但我似乎无法让它发挥作用。建议?谢谢!

4

6 回答 6

14

为了解决您对空白行的最新限制,我会尝试以下方法:

myprops = {}
with open('filename.properties', 'r') as f:
    for line in f:
        line = line.rstrip() #removes trailing whitespace and '\n' chars

        if "=" not in line: continue #skips blanks and comments w/o =
        if line.startswith("#"): continue #skips comments which contain =

        k, v = line.split("=", 1)
        myprops[k] = v

这很清楚,很容易添加额外的约束,而使用 dict 理解会变得非常臃肿。但是,您总是可以很好地格式化它

myprops = dict(line.strip().split('=') 
               for line in open('/Path/filename.properties'))
               if ("=" in line and 
                   not line.startswith("#") and
                   <extra constraint> and
                   <another extra constraint>))
于 2013-11-05T23:09:00.860 回答
6

您应该只使用内置的configparser来读取 ini 样式的配置文件。默认情况下,它允许使用;and进行评论#,因此它应该适合您。

对于.properties文件,您可能需要花点功夫,因为 configparser 通常需要部分名称。您可以通过在阅读时添加一个虚拟部分来轻松做到这一点:

>>> from configparser import ConfigParser
>>> config = ConfigParser()
>>> with open(r'C:\Users\poke\Desktop\test.properties') as f:
        config.read_string('[config]\n' + f.read())

>>> for k, v in config['config'].items():
        print(k, v)

foo bar
bar baz
baz foo

(使用与 mtitan8 相同的示例文件)

对于 Python 2,请from ConfigParser import ConfigParser改用。

于 2013-11-05T21:48:28.077 回答
2

test.txt如您所描述的,给定一个属性文件:

foo=bar
#skip me
bar=baz
baz=foo
#skip me too!

您可以执行以下操作:

>>> D = dict( l.rstrip().split('=') for l in open("test.txt")
              if not l.startswith("#") )
>>> D
{'baz': 'foo', 'foo': 'bar', 'bar': 'baz'}

这看起来就像你说你尝试使用的代码if not line.startswith('#'),所以希望这个工作示例能帮助你查明错误。

于 2013-11-05T21:46:58.080 回答
0

Why force this into one line? Two weeks from now a user will put a space somewhere, or want to use quotes and you have to go unwind the code. Just make a function now which handles the input and be done with it. It also means you can use unit tests to ensure it works and stays working.

Given this input:

foo=bar
#skip me

bar=baz
baz=foo

#skip me too!

The following code will handle it all nicely.

import sys

def parse_line(input):
    key, value = input.split('=')
    key = key.strip()  # handles key = value as well as key=value
    value = value.strip()

    return key, value

if __name__ == '__main__':
    data = {}

    with open(sys.argv[1]) as fp:
        for line in fp:
            line = line.strip()
            if not line or line.startswith('#'):
                continue

            key, value = parse_line(input)
            data[key] = value

    print data

BTW, I like poke's suggestion of using ConfigParser. But the hack of adding a section may or may not work for everyone.

If you want to move the comment checking into the parse_line() function you could return None, None and check for that before putting the key/value pair into the dictionary.

于 2013-11-05T23:14:03.397 回答
0

不应该line.startswith('#')更好地阅读line.strip().startswith('#')吗?

dict(line.strip().split('=') for line in open('/Path/filename.properties') 
                             if not line.strip().startswith('#'))
于 2014-05-09T16:53:38.410 回答
0

没有一个解决方案考虑到该值可以包含=符号。

想象一下以下文件:

baz=foo
foo="foo=bar"
bar=baz

因此,我建议使用以下代码:

>>> D = dict( l.rstrip().split('=', maxsplit=1) for l in open("test.txt") if not l.startswith("#") )
>>> D
{'baz': 'foo', 'foo': '"foo=bar"', 'bar': 'baz'}
于 2020-11-26T13:26:49.500 回答