检查YAML文件中的数据是否在python中按字母顺序排列

时间:2016-11-25 09:14:39

标签: python yaml

我需要在python中检查(验证)YAML文件中的数据是否按某些字段的字母顺序排列(参见下面的示例)。 假设我有一些包含YAML格式数据的文件:

-
  project: presentations/demo1
  description: Some description for demo1 project
  owner: John Doe

-
  project: templates/template_demo
  description: Some template_demo
  owner: Sarah Connor

因此,我必须确保此文件中的数据按“项目”名称排序。 实际上,我有一些解决方案基于获取所有项目名称(来自相应的dicts列表),对它们进行排序,然后与原始YAML文件进行比较。但也许有更好的解决方案。

2 个答案:

答案 0 :(得分:1)

如果你稍微简化这个问题,它就会变成

  

检查列表是否按排序顺序

你可以参考很好的方法here

l = [ 4, 2, 3, 7, 8 ]
# this does not have to be sorted, you just have to check that the
# current entry is less than the next one
all(l[i] <= l[i+1] for i in xrange(len(l)-1))

在你的情况下,它变成

data = parse_yaml_file() # parse your yaml data
is_sorted = all(data[i]['project'] <= data[i+1]['project'] for i in xrange(len(data)-1))

答案 1 :(得分:1)

您应该IMO不要假设您的程序名称与您拥有的程序名称一样简单。如果项目名称变长,则转储YAML的程序可能会将project的标量字符串值包装在多行上。如果名称包含特殊字符(对于YAML),则转储名称的程序将使用标量字符串周围的单引号或双引号。此外,-可能位于您拥有密钥project的行上,而密钥project的值不必位于同一行:

- project:
    presentations/demo1
  description: Some description for demo1 project

YAML解析器会自动正确地重建这样的标量,除了YAML解析器之外,使用其他任何东西都很难正确。

幸运的是,使用YAML解析器很容易在Python中检查你想要的内容:

import ruamel.yaml

with open('input.yaml') as fp:
    data = ruamel.yaml.safe_load(fp)
for idx, d in enumerate(data[:-1]):
    assert d['project'] < data[idx+1]['project']

如果您可以使用相同名称的项目,则应使用<=而不是<。您必须使用pip install ruamel.yaml在virtualenv中安装ruamel.yaml(您肯定使用一个用于开发)。

如果你不想只是想检查YAML,而是生成一个正确订购的YAML,你应该使用:

import ruamel.yaml

with open('input.yaml') as fp:
    data = ruamel.yaml.round_trip_load(fp)
ordered = True
for idx, d in enumerate(data[:-1]):
    if d['project'] > data[idx+1]['project']:
        ordered = False

if not ordered:
    project_data_map = {}
    for d in data:
         project_data_map.setdefault(d['project'], []).append(d)
    out_data = []
    for project_name in sorted(project_data_map):
        out_data.extend(project_data_map[project_name])
    with open('output.yaml', 'w') as fp:
        ruamel.yaml.round_trip_dump(out_data, fp)

这将保留各个映射/ dicts中键的顺序,保留任何注释。

setdefault().append()处理输入中可能双重/重复的任何项目名称作为单独的条目。因此,即使某些项目的项目名称可能相同,输出中的项目数也会与输入相同。