【问题标题】:How to format a string in YAML dump?如何在 YAML 转储中格式化字符串?
【发布时间】:2019-08-07 11:58:17
【问题描述】:

使用 ruamel.yaml 转储 multiline 字符串会导致:

address_pattern_template: "\n^                           #the beginning of the address\
  \ string (e.g. interface number)\n(?P<junkbefore>             #capturing the junk\
  \ before the address\n    \\D?                     #an optional non-digit character\n\
  \    .*?                     #any characters (non-greedy) up to the address\n)\n\
  (?P<address>                #capturing the pure address\n    {pure_address_pattern}\n\
  )\n(?P<junkafter>              #capturing the junk after the address\n    \\D? \
  \                    #an optional non-digit character\n    .*                  \
  \    #any characters (greedy) up to the end of the string\n)\n$                \
  \           #the end of the input address string\n"

代码是这样的:

from ruamel.yaml import YAML
data =dict(
address_pattern_template="""
^                           #the beginning of the address string (e.g. interface number)
(?P<junkbefore>             #capturing the junk before the address
    \D?                     #an optional non-digit character
    .*?                     #any characters (non-greedy) up to the address
)
(?P<address>                #capturing the pure address
    {pure_address_pattern}
)
(?P<junkafter>              #capturing the junk after the address
    \D?                     #an optional non-digit character
    .*                      #any characters (greedy) up to the end of the string
)
$                           #the end of the input address string
"""
)
yaml = YAML(typ='safe', pure=True)
yaml.default_flow_style = False
with open('D:\datadump.yml', 'w') as dumpfile:
    yaml.dump(data, dumpfile)

我想查看可读格式的多行字符串。 IE。换行符用于换行而不是显示为 '\n'。

我可以设置哪些标志/选项使其如下所示:

address_pattern_template: |
  ^                           #the beginning of the address string (e.g. interface number)
  (?P<junkbefore>             #capturing the junk before the address
      \D?                     #an optional non-digit character
      .*?                     #any characters (non-greedy) up to the address
  )
  (?P<address>                #capturing the pure address
      {pure_address_pattern}
  )
  (?P<junkafter>              #capturing the junk after the address
      \D?                     #an optional non-digit character
      .*                      #any characters (greedy) up to the end of the string
  )
  $                           #the end of the input address string

注意,我的程序记录了一个大字典,这样的多行字符串可以出现在字典结构的任何地方和任何深处。因此,遍历字典树并在转储之前加载它们中的每一个(如“我可以控制多行字符串的格式吗?”中所建议的那样)对我来说不是一个好的解决方案。

我想知道是否可以使用参数引导转储程序来识别多行字符串并以块格式转储它们。单行字符串仍然可以与冒号在同一行。这使得日志文件的可读性最高。

【问题讨论】:

标签: string formatting dump ruamel.yaml


【解决方案1】:

首先,您呈现的内容是您想要输出的内容, 不代表您提供的数据。自从 该数据中的多行字符串以换行符开头,块 样式文字标量需要一个块缩进指示符和一个换行符在开始:

address_pattern_template: |2

  ^                           #the beginning of the address string (e.g. interface number)
  .
  .
  .

但拥有这些模式没有意义(至少对我而言) 以换行符开头,所以我将在下面省略它。


如果您不知道多行字符串在数据结构中的位置,但如果可以 在倾倒之前将其就地转换,而不是您可以使用ruamel.yaml.scalarstring:walk_tree

import sys
import ruamel.yaml

data = dict(a=[1, 2, 3, dict(
address_pattern_template="""\
^                           #the beginning of the address string (e.g. interface number)
(?P<junkbefore>             #capturing the junk before the address
    \D?                     #an optional non-digit character
    .*?                     #any characters (non-greedy) up to the address
)
(?P<address>                #capturing the pure address
    {pure_address_pattern}
)
(?P<junkafter>              #capturing the junk after the address
    \D?                     #an optional non-digit character
    .*                      #any characters (greedy) up to the end of the string
)
$                           #the end of the input address string
"""
)])


yaml = ruamel.yaml.YAML()
ruamel.yaml.scalarstring.walk_tree(data)
yaml.dump(data, sys.stdout)

给出:

a:
- 1
- 2
- 3
- address_pattern_template: |
    ^                           #the beginning of the address string (e.g. interface number)
    (?P<junkbefore>             #capturing the junk before the address
        \D?                     #an optional non-digit character
        .*?                     #any characters (non-greedy) up to the address
    )
    (?P<address>                #capturing the pure address
        {pure_address_pattern}
    )
    (?P<junkafter>              #capturing the junk after the address
        \D?                     #an optional non-digit character
        .*                      #any characters (greedy) up to the end of the string
    )
    $                           #the end of the input address string

walk_tree 将多行字符串替换为 LiteralScalarString,在大多数情况下表现得像一个正常的 字符串。

如果该就地转换不可接受,您可以对 首先数据,然后在副本上应用walk_tree。如果那不是可以接受的 由于内存限制,那么您必须为字符串提供替代表示器 如果您有多行字符串,则在表示期间检查。最好你这样做 在子类中的代表:

import sys
import ruamel.yaml

# data defined as before

class MyRepresenter(ruamel.yaml.representer.RoundTripRepresenter):
    def represent_str(self, data):
        style = '|' if '\n' in data else None
        return self.represent_scalar(u'tag:yaml.org,2002:str', data, style=style)


MyRepresenter.add_representer(str, MyRepresenter.represent_str)

yaml = ruamel.yaml.YAML()
yaml.Representer = MyRepresenter
yaml.dump(data, sys.stdout)

它给出了与上一个示例相同的输出。

【讨论】:

  • 我知道潜力在 ruamel.yaml 中,我只是无法从文档中找出这样的解决方案(我没有看到这样的东西)。
  • 正确,换行符不在开头,我只是创建了错误的示例。我用了你的把戏。在我将“typ='safe'”添加到构造函数之前,它就像一个魅力,因为“安全”它给了我“RepresenterError:不能代表一个对象”。它是否将多行字符串视为复杂对象(不安全)而不是普通字符串?
  • 我提出了两个“技巧”,我不确定你用的是哪一个。如果您使用typ='safe' 进行实例化,您将使用SafeRepresenter 而不是RoundTripRepresenter,然后您必须进行调整。当您使用walk_tree 时,您将获得SafeRepresenter 不知道的对象。由于您使用的是 pure=True 并且 RoundTripRepresenter 与 SafeRepresenter 一样安全,所以我认为没有必要使用 typ="safe"
  • 至于文档,我也许应该先在 SO 上抓取我所有的答案,然后将它们作为一个文档发布;-)
  • 我使用您的第一个解决方案建议。确切地说,在我的情况下,“安全”没有多大意义,所以我只是删除了它。越来越多的 ruamel.yaml 用户将非常感谢更详细的文档。我现在将 YAML 用于配置和日志。由于我是这里的初学者,我不允许投票,但已经接受了答案。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2012-03-27
  • 2020-09-30
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多