Чтение и запись файлов yaml с многострочными строками - PullRequest
2 голосов
/ 28 апреля 2019

Мне нужно прочитать файл yaml, изменить его и записать обратно, используя pyYAML. Все работает нормально, кроме случаев, когда в одинарных кавычках есть строковые значения, например если входной файл yaml выглядит как

FOO:
  - Bar: '{"HELLO":
"WORLD"}'

затем читая его как data=yaml.load(open("foo.yaml")) и записывая его yaml.dump(data, fref, default_flow_style=False) генерирует что-то вроде

FOO:
- Bar: '{"HELLO": "WORLD"}'

т.е. без дополнительной строки для значения Bar. Странно то, что если во входном файле есть что-то вроде

FOO:
- Bar: '{"HELLO":

    "WORLD"}'

т.е. одна дополнительная новая строка для значения Bar, а затем ее запись генерирует правильное количество новых строк. Есть идеи, что я делаю не так?

1 Ответ

0 голосов
/ 28 апреля 2019

Вы не делаете ничего плохого, но вам, вероятно, следовало бы прочитать больше спецификации YAML.

Согласно (устаревшей) спецификации 1.1, которую реализует PyYAML, в пределах скаляров с одинарными кавычками :

В многострочном скаляре с одинарными кавычками разрывы строкподвержены (поточному) сгибу строк, и любые конечные пробелы исключаются из содержимого.

и сгиб строки :

Сгиб строки позволяет разбивать длинные строки для удобства чтения, сохраняя при этом исходную семантику одной длинной строки,Когда сворачивание выполнено, любой разрыв строки, заканчивающийся пустой строкой, сохраняется.Кроме того, любые конкретные разрывы строк также сохраняются даже при завершении непустой строки.

Это означает, что ваши первые два примера совпадают, так как разрыв строки читается так, как если быэто пробел.

Третий пример отличается тем, что он фактически содержит символ новой строки после загрузки , потому что «любой разрыв строки, заканчивающийся пустой строкой, сохраняется».Чтобы понять, почему этот дамп возвращается обратно во время загрузки, вы должны знать, что PyYAML не хранит никакой информации о цитировании (ни об одной новой строке в первом примере), он просто загружает этот скаляр в строку Python.Во время дампа PyYAML оценивает, как лучше всего записать эту строку, и варианты, которые он рассматривает (если только вы не попытаетесь принудительно заставить аргументы default_style в dump()): простой стиль, стиль в одинарных кавычках, стиль в двойных кавычках.

PyYAML будет использовать простой стиль (без кавычек), когда это возможно, но поскольку строка начинается с {, это приводит к путанице (коллизии) с использованием этого символа в качестве начала отображения стиля потока.Так что цитирование необходимо.Так как в строке также есть двойные кавычки, и нет символов, которым требуется обратная косая черта, исключающая «чистейшее» представление, которое PyYAML может выбрать, это стиль в одинарных кавычках, и в этом стиле он должен представлять разрыв строки, включая строку emtpy.без скаляра с одинарными кавычками.

Я бы лично предпочел использовать литеральный скаляр в стиле блока для представления вашего последнего примера:

FOO:
- Bar: |
  {"HELLO":
    "WORLD"}

, но если вы загрузите, выгрузите его, используя PyYAML, его читаемостьПотерянный.

Несмотря на то, что в спецификации YAML 1.2 (выпущенной почти 10 лет назад) было сформулировано иначе, сгибание строк работает так же, так что это будет «работать» аналогично более современному загрузчику YAML /самосвал.Мой пакет ruamel.yaml для загрузки / выгрузки YAML 1.2 будет правильно поддерживать стиль блока, если вы установите атрибут preserve_quotes = True в экземпляре YAML(), но он все равно избавится от новой строки в вашем первом примере.Это может быть реализовано (как показывает ruamel.yaml, сохраняя соответствующие позиции новой строки в скалярных скалярах стилей), но никто никогда не просил об этом, вероятно потому, что если люди хотят такого контроля над переносом, для начала они используют стиль блока.

...