首页 > 解决方案 > 包含“ - ”的字符串总是用 ruamel.yaml 换行

问题描述

在 Python 3.7 项目中,我对 YAML 相当陌生,因此决定使用 ruamel.yaml 来帮助我入门。我打算用它来存储与一些视频文件相关的元数据。

我正在使用以下代码创建 YAML 文件:

data[filename] = [{'video': video_path},
                  {'key_frame': frame_path},
                  {'processed': get_timestamp()}]
yaml.dump(data, file_handle)

创建的 YAML 文件如下所示:

video.mp4:
- video: /Users/xyz/video.mp4
- key_frame: /Users/xyz/imgOutput/frame
    - Trigger.jpg
- processed: '2018-07-26 17:09:06'

问题在于 key_frame 是一个名为“frame - Trigger.jpg”的文件。但是,该行总是在文件名中的“-”(即空格-破折号-空格)处中断。结果是,作为一个人类可读的文件,它看起来非常错误。事实上,当它被读回(使用 yaml.open)时,它被正确处理,并被视为应有的单个字符串文件名。只是 YAML 文件中的格式错误。

对原因有什么想法吗?这是预期的行为吗?我已经尝试了许多不同的方式来引用字符串以防万一(这没有什么区别 - 甚至引用它也会分开行),但从代码的角度来看,它从根本上是有效的 - 但作为 YAML 的大卖关键是人类可读的文件,很高兴了解导致它的原因以及如何修复它。

标签: python-3.xyamlruamel.yaml

解决方案


在 YAML 中,纯标量(即没有单引号或双引号的标量)可以包装到空白处的缩进换行符。这就是正在发生的事情。

重现这一点很困难,因为您的问题非常不完整,但是从输出中可以很容易地看到一些事情:

  • data是一个dict
  • filename, video_path, 和frame_path被定义为字符串。
  • file_handle可能是一些为写入而打开的文件流。

其他的则不太容易推断:

  • get_timestamp()不会datetime.datetime()像人们期望的那样从它的名称返回一个实例,而是它的一个字符串表示。为了防止这个字符串被解释为时间戳,它必须被引用。
  • 您正在使用默认YAML()实例(等于typ='rt'),因为非默认实例会以流样式(- {video: /Users/xyz/video.mp4}等)编写叶映射

有了它和适当import的 s 你可以制作一个正常运行的程序:

import datetime
import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML(typ='rt')

def get_timestamp():
    return datetime.datetime(2018, 7, 26, 17, 9, 6).isoformat(sep=' ', timespec='seconds')

data = {}
filename = 'video.mp4'
video_path = '/Users/xyz/video.mp4'
frame_path = '/Users/xyz/imgOutput/frame - Trigger.jpg'
file_handle = sys.stdout

data[filename] = [{'video': video_path},
                  {'key_frame': frame_path},
                  {'processed': get_timestamp()}]
yaml.dump(data, file_handle)

这输出:

video.mp4:
- video: /Users/xyz/video.mp4
- key_frame: /Users/xyz/imgOutput/frame - Trigger.jpg
- processed: '2018-07-26 17:09:06'

所以我们忘记了一些事情,那就是:

yaml.width = 24  # range from 24-38 inclusive

这样你就得到了你的输出:

video.mp4:
- video: /Users/xyz/video.mp4
- key_frame: /Users/xyz/imgOutput/frame
    - Trigger.jpg
- processed: '2018-07-26 17:09:06'

因此,只需删除该yaml.width =行,您就应该一切就绪。


下次请提供一个实际产生输出的最小但完整的功能程序。

我的猜测是您的 frame_path 比您在此处显示的要长得多,并且您没有 user xyz。这会导致您超过默认宽度(在发射器中定义为 be 80)和要换行的普通标量。只需设置 yaml.width = 4096标量长度和嵌套深度所需的任何内容。

当怀疑 YAML 输出是否正确时,将其读回(使用 YAML(typ='safe').load(input_stream),它应该会生成原始数据。


推荐阅读