比用 ruby gsub 替换字符串更有效的方法

More efficient method than string replace with ruby gsub

我有一个第三方 JSON 供稿,它非常庞大 - 包含大量数据。例如

{
   "data": [{
     "name": "ABC",
     "price": "2.50"
   },
   ...
   ]
}

我需要从价格中去掉引号,因为 JSON 提要的消费者需要这样。

为此,我正在执行一个正则表达式来查找价格,然后遍历价格并使用 gsub 进行字符串替换。我是这样做的:

price_strings = json.scan(/(?:"price":")(.*?)(?:")/).uniq
price_strings.each do |price|
  json.gsub!("\"#{price.reduce}\"", price.reduce)
end
json

主要的瓶颈似乎在每个区块上。有更好的方法吗?

如果此 JSON 字符串将在您的应用程序或代码的另一个第三方依赖项中的某个时刻序列化为 Hash(即由您的同事或同事使用)模块),我建议与他们协商,当 json 已经是 Hash 时,按需将价格值从 String 转换为 Numeric,因为这样效率更高,并且允许他们...

...处理边缘情况,如果 "price": "" 我下面的代码将不起作用,因为它会删除 "",并且将是 JSON语法错误。

但是,如果您无法控制这个,或者正在对整个 json 数据进行一次性突变,那么您可以尝试下面的方法吗?

json =
<<-eos
{
  "data": [{
    "name": "ABC",
    "price": "2.50",
    "somethingsomething": {
      "data": [{
        "name": "DEF",
        "price": "3.25", "someprop1": "hello",
        "someprop2": "world"
      }]
    },
    "somethinggggg": {
      "price": "123.45" },
    "something2222": {
      "price": 9.876, "heeeello": "world"
    }
  }]
}
eos

new_json = json.gsub /("price":.*?)"(.*?)"(.*?,|})/, ''

puts new_json
# =>
# {
#   "data": [{
#     "name": "ABC",
#     "price": 2.50,
#     "somethingsomething": {
#       "data": [{
#         "name": "DEF",
#         "price": 3.25, "someprop1": "hello",
#         "someprop2": "world"
#       }]
#     },
#     "somethinggggg": {
#       "price": 123.45 },
#     "something2222": {
#       "price": 9.876, "heeeello": "world"
#     }
#   }]
# }

免责声明:我不是 Regexp 专家。

这真是傻瓜差事。

JSON.parse('{ "price": 2.50 }')
> {price: 2.5}

正如您从这个 javascript 示例中看到的那样,消费端的解析器会将浮点数截断为它想要的任何值。

如果您想提供格式化数字或将格式化留给客户,请使用字符串。

事实上,众所周知,使用浮点数来表示金钱是一个非常糟糕的主意,因为浮点数和双精度数不能准确地表示我们用于金钱的以 10 为底的倍数。 JSON 只有一种数字类型可以同时表示浮点数和整数。

如果客户要对值进行任何类型的计算,您应该使用最低货币面额的整数(欧元和美元的美分)或被消费者解释为 BigDecimal 等效类型的字符串。