V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
baobao1270
V2EX  ›  程序员

YAML 标准的一个 bug

  •  
  •   baobao1270 ·
    baobao1270 · 2022-01-04 14:10:15 +08:00 · 2908 次点击
    这是一个创建于 1047 天前的主题,其中的信息可能已经有所发展或是发生改变。
    ["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 进制数字了
    yaoyao1128
        2
    yaoyao1128  
       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:29: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   ·   实用小工具   ·   2747 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:47 · PVG 20:47 · LAX 04:47 · JFK 07:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.