如何在Python中从YAML存储或读取换行符和回车符

10 投票
1 回答
11176 浏览
提问于 2025-04-18 10:15

我今天一直在为这个问题苦恼,网上也找不到答案。我有一个yaml文档,用来存储我的消息/响应服务器的一些配置,其中一个参数是“message_terminator”。你可以猜到,这个参数就是我的服务器用来识别客户端发送的消息结束符。

\r\n 

这是telnet默认发送的,所以我就把它设置成这样。

Yaml文档:

global:
    server_port: 7040
    bound_ip: 0.0.0.0
    message_terminator: \r\n

我想做的是把message_terminator的值读取为实际的回车和换行,或者把它从字符串表示转换为二进制转义码:回车和换行,而不是字符串表示的"\r\n"

比如说,如果我在python中这样做:

print('\r\n')

它会打印出一个回车和换行,而不是字符本身。但如果我用以下方式从yaml配置中读取这个值:

print(config['global']['message_terminator'])

它就会打印出字符:

\r\n

修改yaml文档并添加引号,比如:

global:
    server_port: 7040
    bound_ip: 0.0.0.0
    message_terminator: '\r\n'

还有

global:
    server_port: 7040
    bound_ip: 0.0.0.0
    message_terminator: b'\r\n'

甚至

global:
    server_port: 7040
    bound_ip: 0.0.0.0
    message_terminator: !!str \r\n

或者

global:
    server_port: 7040
    bound_ip: 0.0.0.0
    message_terminator: !!python/bytes b'\r\n'

都没有效果。当消息结束符被打印出来时,它打印的是字符。当它通过网络发送给客户端时,也是字符。

我还尝试过一些其他方法:

print(bytes(config['global']['message_terminator'], 'utf-8').encode('unicode_escape'))

但仍然只是打印出字符。

如果我完全搞错了或者漏掉了什么,请多多包涵。我还在搞清楚字符串、字节、原始字符串等之间的区别。欢迎任何建议或指点。谢谢你的时间。

编辑 @Jan:在解释器中这样做是有效的。我得到了一个回车和换行的打印,而不是字符。

>>> text = """
... val: "hello\\n\\rnew line"
... """
>>> text
'\nval: "hello\\n\\rnew line"\n'
>>> print(text)

val: "hello\n\rnew line"

>>> import yaml
>>> data = yaml.load(text)
>>> data
{'val': 'hello\n\rnew line'}
>>> print(data['val'])
hello
new line
>>> 

但是在我的主代码中,当我从yaml文件加载时,它打印的是\r\n,而不是实际的回车和换行。这段python代码:

TERM = config['global']['message_terminator']
print(TERM)
print(config['global']['message_terminator'])
print("netcmd server started on port", PORT)

在终端中打印出:

$ python3 netcmd.py
\r\n
\r\n
netcmd server started on port 7040

为了澄清,我想要的是回车和换行的动作,而不是字符表示。

编辑 2:问题解决了。在Jan的更新后,我把yaml文件从:

global:
    server_port: 7040
    bound_ip: 0.0.0.0
    message_terminator: "\\r\\n"

改成了

global:
    server_port: 7040
    bound_ip: 0.0.0.0
    message_terminator: "\r\n"

现在一切都正常工作,python代码从yaml文件中读取并打印出实际的回车和换行。

1 个回答

11

YAML 允许使用反斜杠(\)来转义字符,但你需要把值放在引号里:

>>> text = """
... val: "hello\\n\\rnew line"
... """
...
>>> text
'\nval: "hello\\n\\rnew line"\n'
>>> data = yaml.load(text)
>>> data
{'val': 'hello\n\rnew line'}

所以你包含 global 的文件可以这样工作:

global:
    server_port: 7040
    bound_ip: 0.0.0.0
    message_terminator: "\r\n"

YAML 规范 1.2 的第 5.7 节

5.7. 转义字符

所有不可打印的字符都必须进行转义。YAML 的转义序列使用“\”这种符号,这在大多数现代编程语言中都很常见。每个转义序列都必须被解析成相应的 Unicode 字符。原始的转义序列只是一个展示细节,不能用来传达内容信息。

注意,转义序列只在双引号的标量中被解释。在其他所有标量样式中,“\”字符没有特殊含义,无法使用不可打印的字符。

撰写回答