当我使用PyYAML在Python中编辑YAML文件时,我的所有字符串值都会保存回原始文件而不带引号。
one: valueOne
two: valueTwo
three: valueThree
我希望其中一个字符串用单引号括起来:
one: valueOne
two: valueTwo
three: 'valueThree'
更改default_style
中的yaml_dump
参数会影响整个文件,这是不希望的。我想在单词的开头和结尾添加单引号,我希望用它包围:
valueThreeVariable = "'" + valueThreeVariable + "'"
然而,这最终会导致倾销的YAML看起来像这样:
one: valueOne
two: valueTwo
three: '''valueThree'''
我尝试使用unicode或raw字符串以各种方式转义单引号,但都无济于事。 如何只将我的一个YAML值作为用单引号括起来的字符串?
答案 0 :(得分:4)
您可以将此类功能移植到PyYAML上,但这并不容易。 three
映射中的值必须是与普通字符串不同的类的某个实例,否则YAML转储器不知道它必须执行某些特殊操作,并且该实例将被转储为带引号的字符串。在加载带有单引号的标量时,需要将其创建为此类的实例。除此之外,您可能不希望dict
/ mapping
的密钥在PyYAML默认情况下加扰。
我在我的PyYAML派生ruamel.yaml中为块样式标量执行类似上面的操作:
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.yaml
的{{1}}类:
RoundTripRepresenter
再一次不会抛出错误。上面的内容原则上可以在PyYAML和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
/ safe_load
中完成,但是您需要编写代码来保留键排序以及一些基本功能。 (除此之外,PyYAML仅支持较旧的YAML 1.1标准,而不支持2009年的YAML 1.2标准。)
要在不使用明确safe_dump
转换的情况下使加载工作正常,您可以在调用data['three'] = SingleQuotedScalarString(data['three'])
之前添加以下内容:
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
仍然在没有断言错误的情况下运行,即转储输出等于输入。如上所示,您可以在PyYAML中执行此操作,但它需要更多编码。
使用更现代的版本(ruamel.yaml&gt; 0.14),您可以:
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
并保留单引号。
答案 1 :(得分:0)
我让你的 yaml
事先没有引号,无论之前有没有引号,结果都是一样的。
方法如下:
import yaml
myyaml = """
one: valueOne
two: valueTwo
three: valueThree
"""
# loading the yaml
yaml_dict = yaml.load(myyaml, yaml.FullLoader)
print(yaml_dict)
{'one': 'valueOne', 'two': 'valueTwo', 'three': 'valuethree'}
# Define the following class:
class SingleQuoted(str):
pass
def single_quoted_presenter(dumper, data):
return dumper.represent_scalar('tag:yaml.org,2002:str', data, style="'")
yaml.add_representer(SingleQuoted, single_quoted_presenter)
yaml_dict.update(three = SingleQuoted('valuethree'))
# Now dump as yaml
yaml.dump(yaml_dict, sys.stdout, sort_keys=False, default_flow_style=False)
# save it in a file by using an open file instead of stdout
,它给出了所需的 yaml,如下所示:
one: valueOne
two: valueTwo
three: 'valueThree'