【问题标题】:Check that data in YAML file are in alphabetical order in python检查 YAML 文件中的数据在 python 中是否按字母顺序排列
【发布时间】:2016-11-25 09:14:38
【问题描述】:

我需要在 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

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

【问题讨论】:

  • 为了检查项目是否在YAML文件中排序,您不必对项目名称进行排序,只需将每个项目名称与下一个进行比较,这样更快如果你有很多条目。

标签: python yaml


【解决方案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))

【讨论】:

  • PyYAML load() 不安全,如果您无法完全控制输入 YAML,可能会导致在计算机上执行任意代码。所以这是一个不好的建议,没有必要,因为有safe_load()。除此之外,PyYAML 仍然只支持旧的 YAML 1.1,而不支持 YAML 1.2 规范(2009 年发布)。
  • @Anthon 谢谢!我已经编辑删除了该部分并更多地关注订购。 OP 说他有一些解决方案有效,所以我认为解析已经处理好了。
  • @algrebe,谢谢。你是对的,就我而言,我使用safe_load(),所以我认为你的解决方案更可取。主要问题是关于订购。
【解决方案2】:

您不应在 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']

如果您可以拥有同名的项目,您应该使用&lt;= 而不是&lt;。您必须使用 pip install ruamel.yaml 在您的 virtualenv 中安装 ruamel.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)

这将保留各个映射/字典中键的顺序,保留任何 cmets。

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

【讨论】:

    猜你喜欢
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-31
    相关资源
    最近更新 更多