Python yaml генерирует несколько значений в кавычках

1

Я использую модуль yaml в своем скрипте Python для создания файла YAML. Ниже приведен пример:

import yaml
class MyDumper(yaml.Dumper):

    def increase_indent(self, flow=False, indentless=False):
        return super(MyDumper, self).increase_indent(flow, False)

foo = {
    'instance_type': 'test',
    'hostname': "\"testhost\"",
    'name': 'foo',
    'my_list': [
        {'foo': 'test', 'bar': 'test2'},
        {'foo': 'test3', 'bar': 'test4'}],
    'hello': 'world',
}

print yaml.dump(foo, Dumper=MyDumper, default_flow_style=False)

Выход:

hello: world
hostname: '"testhost"'
instance_type: test
my_list:
  - bar: test2
    foo: test
  - bar: test4
    foo: test3
name: foo

В приведенном выше выводе имя хоста имеет одинарные и двойные кавычки, я хочу только двойные кавычки.

Ожидаемый результат:

hello: world
hostname: "testhost"
instance_type: test
my_list:
  - bar: test2
    foo: test
  - bar: test4
    foo: test3
name: foo
Теги:
python-2.7
yaml
pyyaml

3 ответа

0
Лучший ответ

Вы не можете форсировать котировки в YAML, цитируя части своих данных так же, как и вы. Поскольку цитаты заставляют самосвал применять цитирование к скаляру (т.е. Больше не могут использовать простые скаляры, как для других строковых значений в вашем файле yaml).

Вам нужно создать тип, который сбрасывается кавычками. Наиболее легко это делается с помощью ruamel.yaml (отказ от ответственности: я являюсь автором этой расширенной версии PyYAML, поддерживающей YAML 1.2, поддерживает сохранение комментариев и цитат в обоих направлениях и т.д.).

import sys
import ruamel.yaml
from ruamel.yaml.scalarstring import DoubleQuotedScalarString as dq


yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)

foo = {
    'instance_type': 'test',
    'hostname': dq("testhost"),
    'name': 'foo',
    'my_list': [
        {'foo': 'test', 'bar': 'test2'},
        {'foo': 'test3', 'bar': 'test4'}],
    'hello': 'world',
}


yaml.dump(foo, sys.stdout)

который дает:

instance_type: test
hostname: "testhost"
name: foo
my_list:
  - foo: test
    bar: test2
  - foo: test3
    bar: test4
hello: world

Вы также можете легко загрузить этот вывод и сбросить его, генерируя точно такой же вывод:

from ruamel.yaml.compat import StringIO

buf = StringIO()
yaml.dump(foo, buf)

yaml.preserve_quotes = True
data = yaml.load(buf.getvalue())
yaml.dump(data, sys.stdout)
0

Вы получаете двукратные кавычки, потому что это то, что ваши входные данные имеют. Эта строка:

'hostname': "\"testhost\"",

говорит, что вы хотите, чтобы hosthame имел в качестве значения 10-символьную строку, начинающуюся и заканчивающуюся на ", и это то, что вы видите в yaml. Эта строка с экранированными двойными кавычками "\"testhost\"" и версия yaml '"testhost"' это два разных представления исходных кодов одинаковых данных. Вам нужно только удвоить кавычки вокруг строки в yaml, если вы хотите вставлять в нее специальные символы (например, \n для новой строки). Но yaml.dump() будет заботиться этого для вас.

  • 0
    Это очень странный способ сказать, что простые скаляры в YAML не могут начинаться с двойных кавычек и, следовательно, заключаются в кавычки (именно это указывает стандарт YAML на причину). Вы также не предоставляете способ получить результат, который хочет OP (даже если кавычки не нужны).
  • 0
    Я пытался объяснить yaml.dump() что ему, вероятно, не нужно было направлять yaml.dump() так, как он делает. А также без использования специфичной для yaml терминологии, которую он вполне может не понять.
Показать ещё 1 комментарий
0

Если вы настаиваете на том, чтобы делать это через PyYAML, вы можете объявить свой собственный тип принудительной котировки и добавить своего представителя:

import yaml

class MyDumper(yaml.Dumper):  # your force-indent dumper

    def increase_indent(self, flow=False, indentless=False):
        return super(MyDumper, self).increase_indent(flow, False)

class QuotedString(str):  # just subclass the built-in str
    pass

def quoted_scalar(dumper, data):  # a representer to force quotations on scalars
    return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')

# add the QuotedString custom type with a forced quotation representer to your dumper
MyDumper.add_representer(QuotedString, quoted_scalar)

foo = {
    'instance_type': 'test',
    'hostname': QuotedString('testhost'),  # here the 'magic'
    'name': 'foo',
    'my_list': [
        {'foo': 'test', 'bar': 'test2'},
        {'foo': 'test3', 'bar': 'test4'}],
    'hello': 'world',
}

print(yaml.dump(foo, Dumper=MyDumper, default_flow_style=False))

Что даст вам:

hello: world
hostname: "testhost"
instance_type: test
my_list:
  - bar: test2
    foo: test
  - bar: test4
    foo: test3
name: foo

Отказ от ответственности: Учитывая выбор, я также предпочитаю модуль Anthon ruamel.yaml для своих потребностей YAML.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню