使用PyYAML将文档加载为原始字符串

12 投票
2 回答
23088 浏览
提问于 2025-04-16 22:13

我想解析像下面这样的yaml文档:

meta-info-1: val1
meta-info-2: val2

---

Plain text/markdown content!
jhaha

如果我用PyYAML的load_all来加载这个文档,我会得到以下结果:

>>> list(yaml.load_all(open('index.yml')))
[{'meta-info-1': 'val1', 'meta-info-2': 'val2'}, 'Plain text/markdown content! jhaha']

我想要实现的目标是,这个yaml文件应该包含两个文档,而第二个文档应该被当作一个完整的字符串来理解,更具体地说,就是任何带有markdown格式的大段文本。我不想让它被解析成YAML语法。

在上面的例子中,PyYAML把第二个文档返回为一个完整的字符串。但是如果第二个文档里有一个:字符代替!,我就会遇到语法错误。这是因为PyYAML正在解析那个文档里的内容。

有没有办法告诉PyYAML,第二个文档只是一个原始字符串,不要去解析它呢?

编辑:这里有一些很好的回答。虽然使用引号或字面量语法解决了这个问题,但我希望用户能够写出纯文本,而不需要额外的格式。只需要三个-(或者.)就可以写出一大段纯文本,可能还包括引号。所以,我想知道是否可以告诉PyYAML只解析一个文档,把第二个文档原样给我。

编辑 2:借鉴agf的想法,考虑到第二个文档可能是有效的yaml语法,而不是使用try/except来处理,

config_content, body_content = open(filename).read().split('\n---')
config = yaml.loads(config_content)
body = yaml.loads(body_content)

谢谢agf。

2 个回答

2

如果你只是想在YAML中处理冒号这个字符,可以把它放在单引号或双引号里面。另外,你也可以试试字面量风格,这样你的第二个文档就可以当作一个整体来处理。

6

你可以这样做:

raw = open(filename).read()
docs = []
for raw_doc in raw.split('\n---'):
    try:
        docs.append(yaml.load(raw_doc))
    except SyntaxError:
        docs.append(raw_doc)

如果你无法控制原始文档的格式。

根据PyYAML的文档:

双引号是最强大的格式,也是唯一可以表示任何标量值的格式。使用双引号的标量可以进行转义。通过使用转义序列 \x** 和 \u****,你可以表示任何ASCII或Unicode字符。

所以听起来,如果不是用双引号包起来,就无法在解析时表示任意的标量值。

撰写回答