PyYAML 单引号中的单个字符串
A single string in single quotes with PyYAML
当我在 Python 中使用 PyYAML 编辑 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 上,但这并不容易。 three
映射中的值必须是不同于普通字符串的 class 的某个实例,否则 YAML 转储器不知道它必须做一些特殊的事情并且该实例被转储为带引号的字符串。在加载带有单引号的标量时,需要创建为这个 class 的实例。除此之外,您可能不希望 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
不会抛出断言错误。
要从转储程序开始,您可以 "convert" 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
's RoundTripRepresenter
class:
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['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
有不同的方法可以完成上述操作,包括 class 对 RoundTripConstructor
class 的子class,但实际要更改的方法很小,很容易修补。
结合以上所有内容并稍微清理一下,您会得到:
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)
并保留单引号。
我假设你的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'
当我在 Python 中使用 PyYAML 编辑 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 上,但这并不容易。 three
映射中的值必须是不同于普通字符串的 class 的某个实例,否则 YAML 转储器不知道它必须做一些特殊的事情并且该实例被转储为带引号的字符串。在加载带有单引号的标量时,需要创建为这个 class 的实例。除此之外,您可能不希望 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
不会抛出断言错误。
要从转储程序开始,您可以 "convert" 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
's RoundTripRepresenter
class:
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['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
有不同的方法可以完成上述操作,包括 class 对 RoundTripConstructor
class 的子class,但实际要更改的方法很小,很容易修补。
结合以上所有内容并稍微清理一下,您会得到:
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)
并保留单引号。
我假设你的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'