使用Python在YAML中替换字符串

时间:2018-10-04 19:04:30

标签: python python-3.x yaml

我有以下YAML:

instance:
  name: test
  flavor: x-large
  image: centos7

tasks:
  centos-7-prepare:
    priority: 1
    details::
      ha: 0
      args:
        template: &startup
          name: startup-centos-7
          version: 1.2
        timeout: 1800

  centos-7-crawl:
    priority: 5
    details::
      ha: 1
      args:
        template: *startup
        timeout: 0

第一个任务定义模板名称和版本,然后由其他任务使用。模板定义不应更改,但是其他名称(尤其是任务名称)将更改。

在Python中更改模板名称和版本的最佳方法是什么?

我有以下用于匹配的正则表达式(使用re.DOTALL):

template:.*name: (.*?)version: (.*?)\s

但是到目前为止,还没有弄清re.sub的用法。还是有其他更方便的方法?

2 个答案:

答案 0 :(得分:2)

我会将yaml文件解析为字典,然后编辑字段并将字典写回yaml。

有关在python How can I parse a YAML file in Python中解析yaml的讨论,请参见此问题,但我认为您最终会遇到类似的情况。

def modify(name):
    if name.startswith('p'):
        return [name + '_prd', name]
    elif name.startswith('h'):
        return [name + '_uat', name]
    else:
        return [name]


mod_hostnames = [item
                 for name in hostnames
                 for item in modify(name)]

答案 1 :(得分:2)

对于YAML的这种往返(负载-修改-转储),您应该使用ruamel.yaml(免责声明:我是该软件包的作者)。

如果您输入的是input.yaml,则可以相对容易地找到 name下的versiontemplate并进行更新:

import sys
import ruamel.yaml

def find_template(d):
    if isinstance(d, list):
        for elem in d:
            x = find_template(elem)
            if x is not None:
                return x
    elif isinstance(d, dict):
        for k in d:
            v = d[k]
            if k == 'template':
                if 'name' in v and 'version' in v:
                    return v
            x = find_template(v)
            if x is not None:
                return x
    return None


yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
yaml.preserve_quotes = True

with open('input.yaml') as ifp:
    data = yaml.load(ifp)
template = find_template(data)
template['name'] = 'startup-centos-8'
template['version'] = '1.3'

yaml.dump(data, sys.stdout)

给出:

instance:
  name: test
  flavor: x-large
  image: centos7

tasks:
  centos-7-prepare:
    priority: 1
    'details:':
      ha: 0
      args:
        template: &startup
          name: startup-centos-8
          version: '1.3'
        timeout: 1800

  centos-7-crawl:
    priority: 5
    'details:':
      ha: 1
      args:
        template: *startup
        timeout: 0

请注意,将保留我在输入中插入的(多余的)引号以及注释和别名。