gpt4 book ai didi

python - 使用 PyYAML 用单引号括起来的单个字符串

转载 作者:行者123 更新时间:2023-12-02 07:06:35 24 4
gpt4 key购买 nike

当我使用 PyYAML 在 Python 中编辑 YAML 文件时,所有字符串值都会保存回原始文件,不带引号。

one: valueOne
two: valueTwo
three: valueThree

我希望其中一个字符串用单引号引起来:

one: valueOne
two: valueTwo
three: 'valueThree'

更改 yaml_dump 中的 default_style 参数会影响整个文件,这是我们不希望看到的。我考虑过在我想要包围的字符串的开头和结尾添加单引号:

valueThreeVariable = "'" + valueThreeVariable + "'"

但是,这最终会导致转储的 YAML 看起来像这样:

one: valueOne
two: valueTwo
three: '''valueThree'''

我尝试以各种方式转义单引号,使用 unicode 或原始字符串,但都无济于事。如何使我的 YAML 值之一成为用单引号括起来的字符串?

最佳答案

您可以将此类功能移植到 PyYAML 上,但这并不容易。 two 映射中的值必须是与普通字符串不同的类的某个实例,否则 YAML 转储器不知道它必须执行一些特殊操作,并且该实例将转储为字符串带引号。在加载带有单引号的标量时,需要将其创建为此类的实例。除此之外,您可能不希望您的 dict/mapping 的键像 PyYAML 默认情况下那样被扰乱。

我在我的 PyYAML 衍生品 ruamel.yaml 中做了与上面类似的事情对于 block 样式标量:

import ruamel.yaml

yaml_str = """\
one: valueOne
two: valueTwo
three: |-
valueThree
"""

data = ruamel.yaml.round_trip_load(yaml_str)
assert ruamel.yaml.round_trip_dump(data) == yaml_str

不会抛出断言错误。

<小时/>

要开始使用转储程序,您可以“转换”valueThree 字符串:

import ruamel.yaml
from ruamel.yaml.scalarstring import ScalarString

yaml_str = """\
one: valueOne
two: valueTwo
three: 'valueThree'
"""

class SingleQuotedScalarString(ScalarString):
def __new__(cls, value):
return ScalarString.__new__(cls, value)

data = ruamel.yaml.round_trip_load(yaml_str)
data['three'] = SingleQuotedScalarString(data['three'])

但这无法转储,因为转储程序不知道 SingleQuotedScalarString。您可以通过不同的方式解决这个问题,以下扩展了 ruamel.yamlRoundTripRepresenter 类:

from ruamel.yaml.representer import RoundTripRepresenter
import sys

def _represent_single_quoted_scalarstring(self, data):
tag = None
style = "'"
if sys.version_info < (3,) and not isinstance(data, unicode):
data = unicode(data, 'ascii')
tag = u'tag:yaml.org,2002:str'
return self.represent_scalar(tag, data, style=style)

RoundTripRepresenter.add_representer(
SingleQuotedScalarString,
_represent_single_quoted_scalarstring)

assert ruamel.yaml.round_trip_dump(data) == yaml_str

再次不会抛出错误。原则上,上述操作可以在 PyYAML 和 safe_load/safe_dump 中完成,但您需要编写代码来保留键顺序以及一些基本功能。 (除此之外,PyYAML 仅支持较旧的 YAML 1.1 标准,而不支持 2009 年以来的 YAML 1.2 标准)。

要在不使用显式 data['two'] = SingleQuotedScalarString(data['two']) 转换的情况下进行加载,您可以在调用 之前添加以下内容ruamel.yaml.round_trip_load():

from ruamel.yaml.constructor import RoundTripConstructor
from ruamel.yaml.nodes import ScalarNode
from ruamel.yaml.compat import text_type

def _construct_scalar(self, node):
if not isinstance(node, ScalarNode):
raise ConstructorError(
None, None,
"expected a scalar node, but found %s" % node.id,
node.start_mark)

if node.style == '|' and isinstance(node.value, text_type):
return PreservedScalarString(node.value)
elif node.style == "'" and isinstance(node.value, text_type):
return SingleQuotedScalarString(node.value)
return node.value

RoundTripConstructor.construct_scalar = _construct_scalar

可以通过不同的方法来执行上述操作,包括子类化 RoundTripConstructor 类,但实际需要更改的方法很小,并且可以轻松修补。

<小时/>

结合以上所有内容并进行一些清理,您会得到:

import ruamel.yaml
from ruamel.yaml.scalarstring import ScalarString
from ruamel.yaml.representer import RoundTripRepresenter
from ruamel.yaml.constructor import RoundTripConstructor
from ruamel.yaml.nodes import ScalarNode
from ruamel.yaml.compat import text_type, PY2


class SingleQuotedScalarString(ScalarString):
def __new__(cls, value):
return ScalarString.__new__(cls, value)


def _construct_scalar(self, node):
if not isinstance(node, ScalarNode):
raise ConstructorError(
None, None,
"expected a scalar node, but found %s" % node.id,
node.start_mark)

if node.style == '|' and isinstance(node.value, text_type):
return PreservedScalarString(node.value)
elif node.style == "'" and isinstance(node.value, text_type):
return SingleQuotedScalarString(node.value)
return node.value

RoundTripConstructor.construct_scalar = _construct_scalar


def _represent_single_quoted_scalarstring(self, data):
tag = None
style = "'"
if PY2 and not isinstance(data, unicode):
data = unicode(data, 'ascii')
tag = u'tag:yaml.org,2002:str'
return self.represent_scalar(tag, data, style=style)

RoundTripRepresenter.add_representer(
SingleQuotedScalarString,
_represent_single_quoted_scalarstring)


yaml_str = """\
one: valueOne
two: valueTwo
three: 'valueThree'
"""

data = ruamel.yaml.round_trip_load(yaml_str)
assert ruamel.yaml.round_trip_dump(data) == yaml_str

它仍然运行,没有断言错误,即转储输出等于输入。如前所述,您可以在 PyYAML 中执行此操作,但它需要更多的编码。

<小时/>

使用更现代的版本 (ruamel.yaml>0.14),您可以执行以下操作:

yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True

data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

并保留单引号。

关于python - 使用 PyYAML 用单引号括起来的单个字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37094170/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com