YAML 标准的一个 bug - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
baobao1270
V2EX    程序员

YAML 标准的一个 bug

  •  
  •   baobao1270
    baobao1270 2022-01-04 14:10:15 +08:00 3225 次点击
    这是一个创建于 1375 天前的主题,其中的信息可能已经有所发展或是发生改变。
    ["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
    第 1 条附言    2022-01-05 05:27:55 +08:00

    这个问题找到一个解决办法了,可以开启 yaml tag 来强制标注类型。

    >>> print(yaml.dump(["01", "02", "03", "04", "05", "06", "07", "08", "09"], canOnical=True)) --- !!seq [ !!str "01", !!str "02", !!str "03", !!str "04", !!str "05", !!str "06", !!str "07", !!str "08", !!str "09", ] >>> print(yaml.dump(["01", "02", "03", "04", "05", "06", "07", "08", "09"])) - '01' - '02' - '03' - '04' - '05' - '06' - '07' - 08 - 09 

    我觉得有一个值得思考的地方,就是“遵守标准”就一定对吗?当“遵守标准”和“最大化兼容性”必须进行取舍的时候,我们应该选择哪一个呢?

    20 条回复    2022-04-17 07:28:19 +08:00
    qwerthhusn
        1
    qwerthhusn  
       2022-01-04 14:13:11 +08:00
    目测是库把其当成 8 进制数字了
    yaoyaomoe
        2
    yaoyaomoe  
       2022-01-04 14:17:50 +08:00 via iPhone
    问题的链接已经说了 0 开头 yaml 会认为是 8 进制数字 而对于带 0 开头的十进制数字对于 yaml 是不认可的

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

    https://hitchdev.com/strictyaml/why/implicit-typing-removed/
    cweijan
        10
    cweijan  
       2022-01-04 17:44:41 +08:00
    这是你的解析库有问题, 和 yaml 标准有什么关系
    codehz
        11
    codehz  
       2022-01-04 17:45:26 +08:00 via Android
    类似的问题多了去了
    https://github.com/cblp/yaml-sucks
    mcfog
        12
    mcfog  
       2022-01-04 17:47:25 +08:00
    个人观点,标准过于复杂能力过多导致多数解析器都有各种问题甚至安全漏洞,这是 yaml 标准不够好的地方,不能完全怪实现。在合适的时候,比起花时间找更好的实现,我会选择换更简单从而更不容易出错的标准,例如 json, toml 等
    baobao1270
        13
    baobao1270  
    OP
       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
        14
    ragnaroks  
       2022-01-05 09:03:49 +08:00
    @baobao1270 如果原本是数值 08 解析为 8 没问题,如果是字符串"08"解析为"08"也没问题;如果 "08" 被解析为 8 那才是问题
    ragnaroks
        15
    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
        16
    SmiteChow  
       2022-01-05 10:10:21 +08:00
    不用思考和怀疑,遵循标准这个行为一定是正确的,标准用于规范生产,降低协作成本,最后才是提高效率。
    baobao1270
        17
    baobao1270  
    OP
       2022-01-05 10:17:29 +08:00
    @ragnaroks “如果原本是数值 08 解析为 8 没问题”这句话是有问题的,08 应该转化为"08"而不是 8

    “如果 "08" 被解析为 8 那才是问题” 其实这就是问题本身YAML 认为 08 和 "08" 是同一个东西
    2i2Re2PLMaDnghL
        18
    2i2Re2PLMaDnghL  
       2022-01-05 12:9:30 +08:00
    YAML 标准 1.2 中将八进制数的表示方式改为 0o777 这样(小写字母 o )
    2i2Re2PLMaDnghL
        19
    2i2Re2PLMaDnghL  
       2022-01-05 13:46:59 +08:00
    我以各种关键词搜索了一下标准,发现标准中似乎没有规定以 `0` 开头的数字,比如
    ```
    08
    ```
    (也包括 09 )的实际含义。(可能是我看漏了)
    rv54ntjwfm3ug8
        20
    rv54ntjwfm3ug8  
       2022-04-17 07:28:19 +08:00
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1045 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 18:25 PVG 02:25 LAX 11:25 JFK 14:25
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86