Как я могу выполнить конкатенацию строк или замену строк в YAML?

У меня есть это:

user_dir: /home/user
user_pics: /home/user/pics

Как я могу использовать user_dir для user_pics? Если бы мне пришлось указать другие подобные свойства, это было бы не очень СУХОЕ.


person Geo    schedule 30.03.2011    source источник


Ответы (7)


Вы можете использовать повторяющийся узел, например:

user_dir: &user_home /home/user
user_pics: *user_home

Я не думаю, что вы можете объединить, поэтому это не сработает:

user_dir: &user_home /home/user
user_pics: *user_home/pics
person Brian Wells    schedule 10.05.2011
comment
Спасибо, что прояснили это. Глупо было думать, что это возможно. - person Shawn Vader; 31.01.2016
comment
tbh - я не понимаю, в чем смысл этих указателей, если вы не можете использовать их для объединения ..: / - person Bruno Ambrozio; 10.10.2020

Это удивительно, поскольку цель привязок и ссылок YAML состоит в том, чтобы исключить дублирование файлов данных YAML, что не существует встроенного способа объединения строк с использованием ссылок. Ваш вариант использования создания имени пути из частей является хорошим примером - таких применений должно быть много.

К счастью, есть простой способ добавить конкатенацию строк в YAML с помощью настраиваемых тегов в Python.

import yaml

## define custom tag handler
def join(loader, node):
    seq = loader.construct_sequence(node)
    return ''.join([str(i) for i in seq])

## register the tag handler
yaml.add_constructor('!join', join)

## using your sample data
yaml.load("""
user_dir: &DIR /home/user
user_pics: !join [*DIR, /pics]
""")

Что приводит к:

{'user_dir': '/home/user', 'user_pics': '/home/user/pics'}

Вы можете добавить в массив больше элементов, например " " или "-", если строки должны быть разделены.

person Chris Johnson    schedule 22.04.2014
comment
Эээ ... Итак, какое это имеет отношение к YAML, языку разметки, независимому от Python, Haskell или чего-то еще? - person Hi-Angel; 02.09.2016
comment
Спецификация YAML гласит: Явная типизация обозначается тегом с восклицательным знаком («!») ... Также могут использоваться локальные теги, специфичные для приложения. Я предоставил реализацию явного типа, которая соответствует спецификации. Реализация должна быть на каком-то языке. Я использовал Python, потому что OP сказал, что хочет более СУХОЙ подход для своего YAML, а DRY - это термин, который чаще всего используется людьми, занимающимися Python. Тот же пользовательский тег может быть реализован на других языках. Другими словами, то, что запросил OP, недоступно в ванильном YAML, но доступно через механизм расширения, определенный YAML. - person Chris Johnson; 02.09.2016
comment
@ Hi-Angel Всякий раз, когда кто-то использует YAML, он будет использовать какой-нибудь синтаксический анализатор, написанный на каком-то конкретном языке - подобное расширение может быть сделано на этом языке. Это всего лишь один пример для Python. - person Ken Williams; 05.03.2020
comment
@KenWilliams, хорошо, я буду иметь это в виду, поэтому в следующий раз, когда я столкнусь с проприетарным приложением, использующим YAML для настройки, если мне понадобится конкатенация строк, я должен попросить авторов предоставить мне исходный код парсера и всю необходимую сборку системные части. - person Hi-Angel; 05.03.2020
comment
@ Hi-Angel Как сказал Крис Джонсон, это явный механизм расширения, определенный самой спецификацией YAML. И не нужно лукавить. - person Ken Williams; 07.03.2020
comment
@KenWilliams, ладно, может я запутался, извини, если это так. Если это правда, я думаю, что Крис Джонсон может получить гораздо больше голосов и гораздо меньше запутанных комментариев, если он покажет полный пример YAML, который использует этот механизм расширения. Потому что прямо сейчас, когда я смотрю на ответ, я в основном вижу предложение изменить код парсера YAML. Может быть, ссылка на какой-то другой ответ SO, в котором говорится, что даже если у вас нет исходного кода для приложения, вы все равно можете легко расширить синтаксический анализатор YAML на языке, который вам нравится, следующим образом ... - это очень помогло бы. - person Hi-Angel; 07.03.2020
comment
Существующий ответ не изменяет код парсера YAML. Это не предполагает, что у вас есть доступ к исходному коду пакета yaml. Он просто использует свои общедоступные API-интерфейсы, чтобы расширить его так, как это разрешено спецификацией YAML. - person Ken Williams; 11.03.2020
comment
Привет @Dany - Спасибо за код. Но это не работает, когда мой YAML является файлом. Получаю: не удалось определить конструктор для тега! Join. Не могли бы вы помочь, пожалуйста? Я также пробовал добавить двойной! но потом я не смог определить конструктор для тега 'tag: yaml.org, 2002: join' - person Bruno Ambrozio; 10.10.2020
comment
@BrunoAmbrozio привет! Это ответ Криса Джонсона, я только что редактировал его, и это было больше года назад, я ничего об этом не помню, извините. Вы должны спросить Криса Джонсона - person Dany; 11.10.2020
comment
Как я могу использовать его в конвейере Azure DevOps? - person user1700890; 21.12.2020

Если вы используете python с PyYaml, соединение строк возможно в файле YAML. К сожалению, это всего лишь решение на Python, а не универсальное:

с os.path.join:

user_dir: &home /home/user
user_pics: !!python/object/apply:os.path.join [*home, pics]

с string.join (для полноты картины - этот метод может использоваться для нескольких форм соединения строк:

user_dir: &home /home/user
user_pics: !!python/object/apply:string.join [[*home, pics], /]
person user2502636    schedule 06.03.2014
comment
Понятно, что означает этот подход - вы разрешаете парсеру Pyyaml ​​выполнять произвольный код Python из входного файла yaml. Это чрезвычайно опасная проблема безопасности, если вы не контролируете источник ввода. Многие программы будут использовать функцию yaml.safe_load(), чтобы избежать проблем с безопасностью. В этом случае ваш код не будет работать. - person Chris Johnson; 30.08.2015
comment
у вас есть пример python3 для объединения строк? cannot find module 'str' (No module named 'str') - person Jeremy Leipzig; 16.06.2016

Я бы использовал массив, а затем присоединил бы строку вместе с текущим символом разделителя ОС

нравится:

default: &default_path "you should not use paths in config"
pictures:
  - *default_path
  - pics
person Adam    schedule 27.02.2014

Мне кажется, что сам YAML не определяет способ сделать это.

Хорошая новость заключается в том, что потребитель YAML может понимать переменные.
Что будет использовать ваш YAML?

person Arnis Lapsa    schedule 30.03.2011
comment
Мой файл yaml служит файлом конфигурации. То, что я вставил выше, было просто примером, чтобы проиллюстрировать проблему. - person Geo; 30.03.2011

string.join() не будет работать в Python3, но вы можете определить !join следующим образом:

import functools
import yaml

class StringConcatinator(yaml.YAMLObject):
    yaml_loader = yaml.SafeLoader
    yaml_tag = '!join'
    @classmethod
    def from_yaml(cls, loader, node):
        return functools.reduce(lambda a, b: a.value + b.value, node.value)

c=yaml.safe_load('''
user_dir: &user_dir /home/user
user_pics: !join [*user_dir, /pics]''')
print(c)
person bryan    schedule 19.06.2019

По состоянию на август 2019 г.:

Чтобы решение Криса работало, вам действительно нужно добавить Loader=yaml.Loader в yaml.load(). В конечном итоге код будет выглядеть так:

import yaml

## define custom tag handler
def join(loader, node):
    seq = loader.construct_sequence(node)
    return ''.join([str(i) for i in seq])

## register the tag handler
yaml.add_constructor('!join', join)

## using your sample data
yaml.load("""
user_dir: &DIR /home/user
user_pics: !join [*DIR, /pics]
""", Loader=yaml.Loader)

См. эту проблему GitHub для дальнейшего обсуждения.

person bmiselis    schedule 02.08.2019