Специальный символ Python YAML и несколько строк

1

У меня есть файл my_yaml.yml со следующим содержимым:

my_yaml:
  person: >
    John|Doe|48,
    Jack|Black|39
  skills:
    - name: superhero
      abilities:
        - swim
        - run
  special_chars:
    - '! | " "'
    - '+ | " "'
    - '\ | " "'
    - 'Á | "A"'
    - 'É | "E"'
    - 'Ű | "U"'
    - 'Û | "U"'

Я хочу загрузить его, а затем сбрасывать в файл my_yaml_new.yml имеющий полностью тот же формат и символы, что и исходный входной файл. Мой код:

import yaml
my_yaml = yaml.load(open('my_yaml.yml', encoding='utf8'))  # without "utf8" encoding I get "'charmap' codec can't decode byte..." error

Я могу dump его в консоль, но 1) порядок abilities и name изменился :(

yaml.dump(my_yaml, default_flow_style=False, allow_unicode=True)

Результат:

'my_yaml:\n  person: >\n    John|Doe|48, Jack|Black|39\n  skills:\n  - abilities:\n    - swim\n    - run\n    name: superhero\n  special_chars:\n  - \'! | " "\'\n  - + | " "\n  - \\ | " "\n  - Á | "A"\n  - É | "E"\n  - Ű | "U"\n  - Û | "U"\n'

И когда я пытаюсь свалить файл:

with open('my_yaml_new.yml', 'w') as outfile:
    yaml.dump(my_yaml, outfile, default_flow_style=False, allow_unicode=True)

2) Я получаю следующую ошибку из-за символа Û:

UnicodeEncodeError: кодек 'charmap' не может кодировать символ '\ xdb' в позиции 0: символьные карты до неопределенных

Если я удалю эту строку из файла ввода my_yaml.yml то выше дампа будет успешным, но 3) мои несколько строк в строке person войдут в одну строку :(

my_yaml:
  person: >
    John|Doe|48, Jack|Black|39
  skills:
  - abilities:
    - swim
    - run
    name: superhero
  special_chars:
  - '! | " "'
  - + | " "
  - \ | " "
  - Á | "A"
  - É | "E"
  - Ű | "U"

4) А также мои одиночные кавычки (') исчезли из special_chars :(

5) Также обратите внимание, что элементы skills не имеют отступов :(

Я пробовал эти решения без успеха. И ни import ruamel.yaml as yaml помог import ruamel.yaml as yaml.


ОБНОВИТЬ

Хорошо, следующий отличный пакет решает проблемы 1) & 4), и я могу заменить > на | при многострочных значениях, так что 3) также решается. И, может быть, 5) не является большой проблемой. Но я все еще борюсь со специальными персонажами, такими как Û или Ǘ поэтому я все еще ищу решение проблемы 2)...

from ruamel import yaml

    my_yaml = yaml.round_trip_load(open('dmy_yaml.yml', encoding='utf8'), preserve_quotes=True)
    with open('my_yaml_new.yml', 'w') as outfile:
        yaml.round_trip_dump(my_yaml, outfile, default_flow_style=False, allow_unicode=True)
Теги:
yaml
ruamel.yaml
pyyaml

1 ответ

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

Я не уверен, почему вы столкнулись с проблемами с unicode. Если у вас есть my_yaml.yml и программа try.py:

import sys
import ruamel.yaml

with open('my_yaml.yml') as fp:
    yaml_str = fp.read().replace(': >\n', ': |\n')

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=2, sequence=4, offset=2)
yaml.preserve_quotes = True
data = yaml.load(yaml_str)
new_file = 'my_yaml_new.yml'
with open(new_file, 'w') as ofp:
    yaml.dump(data, ofp)

то это производит:

my_yaml:
  person: |
    John|Doe|48,
    Jack|Black|39
  skills:
    - name: superhero
      abilities:
        - swim
        - run
  special_chars:
    - '! | " "'
    - '+ | " "'
    - '\ | " "'
    - 'Á | "A"'
    - 'É | "E"'
    - 'Ű | "U"'
    - 'Û | "U"'

в virtualenv для Python2 и Python3 с ruamel.yaml 0.15.40.

Я использовал:

for n in 2 3 ; do  mktmpenv -p /opt/python/$n/bin/python -qq -i ruamel.yaml; python --version; python try.py; deactivate; done

который, конечно, полагается на (последние) версии Python 2 и 3 для установки в /opt/python/2 resp. /opt/python/3 (которые они находятся в моей системе разработки Linux).

Обратите внимание, что Unicode не показывает проблем, что yaml.indent(mapping=2, sequence=4, offset=2) сохраняет исходный отступ, но вам все равно нужно сменить сложенный многострочный скалярный на литеральный стиль (который я во время чтения в yaml_str), поскольку ruamel.yaml не поддерживает сохранение этого (в первую очередь потому, что нет простого способа показать исходные точки складывания прозрачным способом).

  • 0
    Спасибо, это решение работает отлично !!! Я не знаю почему, но мне всегда нужно принудительно вызывать encoding='utf-8 когда я читаю файл, пусть это будет pandas.read_csv() или просто with open() . ( sys.getdefaultencoding() возвращается с utf-8 ...)
  • 0
    Возможно, это связано с компиляцией вашего Python, но я не уверен.

Ещё вопросы

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