【问题标题】:How can I do string concatenation, or string replacement in YAML?如何在 YAML 中进行字符串连接或字符串替换?
【发布时间】:2011-07-25 22:28:09
【问题描述】:

我有这个:

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

如何将user_dir 用于user_pics?如果我必须像这样指定其他属性,它不会很干燥。

【问题讨论】:

    标签: concatenation yaml


    【解决方案1】:

    你可以使用一个重复的节点,像这样:

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

    我不认为你可以连接,所以这不会工作:

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

    【讨论】:

    • 感谢您解决这个问题。愚蠢的我认为这是可能的。
    • tbh - 如果您不能使用这些指针进行连接,我不明白这些指针的意义何在..:/
    • 这个answer 展示了如何定义 !join 以便您可以连接。
    【解决方案2】:

    令人惊讶的是,由于 YAML 锚点和引用的目的是从 YAML 数据文件中排除重复,因此没有使用引用连接字符串的内置方法。您从部件构建路径名的用例就是一个很好的例子——肯定有很多这样的用途。

    幸运的是,有一种简单的方法可以通过 Python 中的自定义标签将字符串连接添加到 YAML。

    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'}
    

    如果字符串需要分隔,您可以向数组中添加更多项,例如 " " 或 "-"。

    【讨论】:

    • Err... 那么,它与 YAML 有什么关系?YAML 是一种独立于 Python、Haskell 等的标记语言?
    • YAML 规范说:“显式类型用带有感叹号 (“!”) 的标签来表示……也可以使用特定于应用程序的本地标签。”我提供了一个符合规范的显式类型的实现。实现必须使用某种语言。我使用 Python 是因为 OP 说他希望为他的 YAML 提供更“DRY”的方法,而 DRY 是 Python 人最常使用的术语。相同的自定义标签可以用其他语言实现。换句话说,OP 要求的内容在 vanilla YAML 中不可用,但可以通过 YAML 定义的扩展机制获得。
    • @KenWilliams 好的,我会记住的,所以下次遇到使用YAML进行配置的专有应用程序时,如果我需要字符串连接,我应该请作者提供给我解析器源代码和所有必要的构建系统部分。
    • @Hi-Angel 正如 Chris Johnson 所说,这是 YAML 规范本身定义的显式扩展机制。而且没有必要刻薄。
    • 现有答案不修改 YAML 解析器代码。它不假定您可以访问yaml 包的源代码。它只是使用其公共 API 以 YAML 规范允许的方式对其进行扩展。
    【解决方案3】:

    如果您在 PyYaml 中使用 python,则可以在 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], /]
    

    【讨论】:

    • 要清楚这种方法的含义——您允许 Pyyaml 解析器从 yaml 输入文件执行任意 Python 代码。如果您不控制输入源,这是一个极其危险的安全问题。许多程序会使用yaml.safe_load() 函数来避免安全问题。在这种情况下,您的代码将无法工作。
    • 你有用于字符串连接的 python3 示例吗? cannot find module 'str' (No module named 'str')
    【解决方案4】:

    我会使用一个数组,然后将字符串与当前的操作系统分隔符连接在一起

    像这样:

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

    【讨论】:

      【解决方案5】:

      在我看来,YAML 本身 does not define way to do this。

      好消息是 YAML 使用者或许能够理解变量。
      什么将使用您的 YAML?

      【讨论】:

      • 我的 yaml 文件用作配置文件。我上面贴的只是一个例子,用来说明问题。
      • @ArnisL。 for example this one 在构建单独的模块时定义源代码目录的路径。
      【解决方案6】:

      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)
      

      【讨论】:

        【解决方案7】:

        截至 2019 年 8 月:

        要使Chris' 解决方案有效,您实际上需要将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)
        

        更多讨论请见this GitHub issue。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-08-05
          • 2010-09-27
          • 1970-01-01
          • 2010-12-23
          • 2022-11-25
          • 2020-10-06
          • 1970-01-01
          相关资源
          最近更新 更多