YAML 标准的一个 bug

2022-01-04 14:10:15 +08:00
 baobao1270
["01", "02", "03", "04", "05", "06", "07", "08", "09"]

这个数组转换为 YAML:

 - '01'
 - '02'
 - '03'
 - '04'
 - '05'
 - '06'
 - '07'
 - 08
 - 09

这样的行为是符合标准的。

但是,如果你转换回来:

["01", "02", "03", "04", "05", "06", "07", 8, 9]

大家可以试试自己常用的程序有没有这样的问题。

Reference:

  1. https://github.com/nodeca/js-yaml/issues/320
  2. https://github.com/yaml/pyyaml/issues/577
2908 次点击
所在节点    程序员
20 条回复
qwerthhusn
2022-01-04 14:13:11 +08:00
目测是库把其当成 8 进制数字了
yaoyao1128
2022-01-04 14:17:50 +08:00
问题的链接已经说了 0 开头 yaml 会认为是 8 进制数字 而对于带 0 开头的十进制数字对于 yaml 是不认可的

yaml.org/type/int.html
baobao1270
2022-01-04 15:05:21 +08:00
@yaoyao1128 问题就在这里呀,你的实现要保证 load 和 dump 一致啊
kingxiangqi
2022-01-04 16:01:34 +08:00
离谱。字符串不应该始终保持原样吗?为什么会被当做数字处理?
ragnaroks
2022-01-04 16:26:48 +08:00
ysc3839
2022-01-04 16:30:42 +08:00
yaml 本来设计就不是让程序生成的吧?设计是让人手写,程序读取,因此弱化了类型系统,理论上来说 yaml 只有文本的,没有整数啥的。你举的例子是因为程序自动进行了类型转换。
makelove
2022-01-04 17:05:07 +08:00
@ysc3839 没道理不适合程序生成吧?比如 pnpm 的自动生成并更新的 lockfile 就是 yaml 的
ysc3839
2022-01-04 17:32:31 +08:00
@makelove 我说的有问题,是指不适合楼主所说的“保证 load 和 dump 一致”这种情况。相反,JSON 是有库可以实现保留大部分格式的,包括注释也能保留。
mcfog
2022-01-04 17:41:34 +08:00
类似的还有挪威问题:用 yaml 写国家码 US CN JP KR 不亦乐乎直到有一天遇到了挪威…

https://hitchdev.com/strictyaml/why/implicit-typing-removed/
cweijan
2022-01-04 17:44:41 +08:00
这是你的解析库有问题, 和 yaml 标准有什么关系
codehz
2022-01-04 17:45:26 +08:00
类似的问题多了去了
https://github.com/cblp/yaml-sucks
mcfog
2022-01-04 17:47:25 +08:00
个人观点,标准过于复杂能力过多导致多数解析器都有各种问题甚至安全漏洞,这是 yaml 标准不够好的地方,不能完全怪实现。在合适的时候,比起花时间找更好的实现,我会选择换更简单从而更不容易出错的标准,例如 json, toml 等
baobao1270
2022-01-05 05:17:24 +08:00
@ragnaroks 你确定是正常的吗?我这里显示是这样的 'number-list': [ '01', '02', '03', '04', '05', '06', '07', 8, 9, '10', '11' ] 可能你没有理解我的意思,符合标准的解析器应该把它解析为 'number-list': [ '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11' ]
而且巧了我就是在 Minecraft 里碰到这个问题的。

@cweijan 问题就在这里,libyaml 、js-yaml 、pyyaml 等库都认为把 "08" 转换成 08 是符合标准的,但是把 08 转换成 int 8 也是符合标准的。他们都选择了“遵从标准实现”而不是“最大化兼容性”。

@ysc3839 #8 @mcfog 问题就是在这里,你没法控制不是你写的代码,人家要用 YAML 还要多次 load 和 dump 你也没法改啊,比如 Minecraft 的 mod 实现的“导出配置”的功能。
ragnaroks
2022-01-05 09:03:49 +08:00
@baobao1270 如果原本是数值 08 解析为 8 没问题,如果是字符串"08"解析为"08"也没问题;如果 "08" 被解析为 8 那才是问题
ragnaroks
2022-01-05 09:06:12 +08:00
写了个 bukkit 插件测试

List<int> list1=new List<int>{2,4,6,8,10};
List<string> list2=new List<string>{"2","4","6","8","10"};

plugin.yml:

list1
- 2
- 4
- 6
- 8
- 10

list2
- "2"
- "4"
- "6"
- "8"
- "10"
SmiteChow
2022-01-05 10:10:21 +08:00
不用思考和怀疑,遵循标准这个行为一定是正确的,标准用于规范生产,降低协作成本,最后才是提高效率。
baobao1270
2022-01-05 10:17:29 +08:00
@ragnaroks “如果原本是数值 08 解析为 8 没问题”这句话是有问题的,08 应该转化为"08"而不是 8

“如果 "08" 被解析为 8 那才是问题” 其实这就是问题本身——YAML 认为 08 和 "08" 是同一个东西
2i2Re2PLMaDnghL
2022-01-05 12:29:30 +08:00
YAML 标准 1.2 中将八进制数的表示方式改为 0o777 这样(小写字母 o )
2i2Re2PLMaDnghL
2022-01-05 13:46:59 +08:00
我以各种关键词搜索了一下标准,发现标准中似乎没有规定以 `0` 开头的数字,比如
```
08
```
(也包括 09 )的实际含义。(可能是我看漏了)
rv54ntjwfm3ug8
2022-04-17 07:28:19 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/826093

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX