How can I do string concatenation, or string replacement in YAML?

后端 未结 7 2197
深忆病人
深忆病人 2020-12-01 08:38

I have this:

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

How could I use the user_dir for user_pics? If I have to specify

相关标签:
7条回答
  • 2020-12-01 09:20

    string.join() won't work in Python3, but you can define a !join like this:

    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)
    
    0 讨论(0)
  • 2020-12-01 09:21

    It's surprising, since the purpose of YAML anchors & references is to factor duplication out of YAML data files, that there isn't a built-in way to concatenate strings using references. Your use case of building up a path name from parts is a good example -- there must be many such uses.

    Fortunately there's a simple way to add string concatenation to YAML via custom tags in 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]
    """)
    

    Which results in:

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

    You can add more items to the array, like " " or "-", if the strings should be delimited.

    0 讨论(0)
  • 2020-12-01 09:24

    If you are using python with PyYaml, joining strings is possible within the YAML file. Unfortunately this is only a python solution, not a universal one:

    with os.path.join:

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

    with string.join (for completeness sake - this method has the flexibility to be used for multiple forms of string joining:

    user_dir: &home /home/user
    user_pics: !!python/object/apply:string.join [[*home, pics], /]
    
    0 讨论(0)
  • 2020-12-01 09:27

    I would use an array, then join the string together with the current OS Separator Symbol

    like this:

    default: &default_path "you should not use paths in config"
    pictures:
      - *default_path
      - pics
    
    0 讨论(0)
  • 2020-12-01 09:28

    As of August 2019:

    To make Chris' solution work, you actually need to add Loader=yaml.Loader to yaml.load(). Eventually, the code would look like this:

    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)
    

    See this GitHub issue for further discussion.

    0 讨论(0)
  • 2020-12-01 09:39

    Seems to me that YAML itself does not define way to do this.

    Good news are that YAML consumer might be able to understand variables.
    What will use Your YAML?

    0 讨论(0)
提交回复
热议问题