【问题标题】:Preventing converting string into octal number in Ruby防止在Ruby中将字符串转换为八进制数
【发布时间】:2015-10-13 08:07:55
【问题描述】:

假设我们有以下 ruby​​ 代码

require 'yaml'

h={"key"=>[{"step1"=>["0910","1223"]}]}
puts h.to_yaml

"0910" 是一个字符串 但是to_yaml转换后,字符串变成了八进制数。

---
key:
- step1:
  - 0910
  - '1223'

问题是我无法更改 h 变量。我是从外面收到的,我需要在不改变的情况下解决问题。

【问题讨论】:

  • 您是否尝试将其解析回来?

标签: ruby yaml


【解决方案1】:

您误认为 YAML 输出中有一个八进制数。 YAML spec 有两次指八进制,并且都清楚地表明 YAML 文件中的八进制数以 0o 开头(这类似于 Ruby 和较新版本的 Python 用于指定八进制;Python 也删除了在版本 3 中仅支持 0 八进制,Ruby 似乎还没有做到这一点)。

表示仅以0 开头的八进制整数的习惯已在许多语言中被证明是令人困惑的,并且六年前已从 YAML 规范中删除。可能是您的解析器仍然支持它,但它不应该。

在任何情况下,字符89 永远不会出现在表示为八进制数的整数中,因此在这种情况下,不会混淆那个不带引号的标量是一个数字。 字符串 1223 可以解释为普通整数,因此它必须始终表示为带引号的字符串标量。

有趣的是看看当你转储字符串"0708"时会发生什么。如果您的 YAML 库是最新的规范(版本 1.2),它可以将其转储为不带引号的标量。由于前导零后面没有o(或x),因此不会混淆这可能是八进制数(分别是十六进制),但是为了与旧解析器(从2009年之前)兼容,您的为了安全起见,解析器可能只是引用它。

【讨论】:

  • 检查转储 0708 时会发生什么我使用了这段代码。要求 'psych' h={"key"=>[{"step1"=>['0910',"1223","0708","08","0777"]}]} puts Psych.dump(h) ` 结果:--- 键:- step1:- 0910 - '1223' - 0708 - 08 - '077'
  • @user3419308 所以解析器要么是 1.2 并且可以安全地使用八进制字符,要么它只兼容 YAML 1.1。您可以尝试的另一件事是指定 0o77(不带引号)并查看是否加载(抱歉,我的系统上没有安装 ruby​​,所以不能自己尝试)。
  • 您如何看待,避免这种转换的最佳解决方案是什么?
  • @user3419308 我不确定你所说的转换是什么意思。一个 ruby​​ 字符串被表示为一个简单的标量,如果可以的话,或者作为一个带引号的标量,如果需要的话。我的 (Python) YAML 库有一个选项可以指定默认情况下如何表示字符串标量,这样您就可以强制它引用所有内容。如果您的图书馆没有这样的选择,您必须接受它选择的表示形式(这是 IMO 而不是转换)
【解决方案2】:

根据以 0 为前缀的 YAML spec 数字表示八进制基数(就像在 Ruby 中一样)。但是 08 不是有效的八进制数,因此不会被引用。

当您从 YAML 文件加载此数据时,数据会完全按照您的需要显示。

0> h={"key"=>[{"step1"=>["0910","1223"]}]}
=> {"key"=>[{"step1"=>["0910", "1223"]}]}

0> yaml_h = h.to_yaml
=> "---\nkey:\n- step1:\n  - 0910\n  - '1223'\n"

0> YAML.load(yaml_h)
=> {"key"=>[{"step1"=>["0910", "1223"]}]}

如果您不能使用此状态下的数据,也许您可​​以扩展问题并提供更多详细信息。

【讨论】:

  • 您引用了超过 6 年的规范。 YAML 1.2 指定八进制数应以0o 开头。当然可能是库试图向后兼容,但这不能从这个有限的输入中推断出来。
【解决方案3】:

有一个类似的任务。 我在 secrets.yml 中使用:

processing_eth_address: "0x5774226def39e67d6afe6f735f9268d63db6031b"

processing_eth_address: <%= "\'#{ENV["PROCESSING_ETH_ADDRESS"]}\'" %>

【讨论】:

    【解决方案4】:

    我的 Ruby 没有进行这种八进制转换,但我在日期方面遇到了类似的问题。我用 to_yaml(canonical: true) 来解决这个问题。它更冗长,但它正确

    {"date_of_birth" => "1991-02-29"}.to_yaml
    => "---\ndate_of_birth: 1991-02-29\n"
    {"date_of_birth" => "1991-02-29"}.to_yaml(canonical: true)
    => "---\n{\n  ? \"date_of_birth\"\n  : \"1991-02-29\",\n}\n"
    

    【讨论】:

      猜你喜欢
      • 2021-09-07
      • 1970-01-01
      • 1970-01-01
      • 2016-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-13
      相关资源
      最近更新 更多