You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby中如何无转换解析JSON?需保留所有值的原始内容与格式

Ruby JSON库:解析时保留所有值为原始字符串的方案

方案1:自定义解析器(基于默认json库)

Ruby默认的json库没有直接提供"全字符串解析"的选项,但你可以自己写一个轻量的解析器,遍历JSON字符串时把所有值(包括数字、布尔、null)都原样保留为字符串,完全跳过类型转换:

require 'json'

class RawJSONParser
  def parse(source)
    @source = source
    @index = 0
    skip_whitespace
    parse_value
  end

  private

  def skip_whitespace
    while @index < @source.length && @source[@index] =~ /\s/
      @index += 1
    end
  end

  def parse_value
    skip_whitespace
    case @source[@index]
    when '"' then parse_string
    when '{' then parse_object
    when '[' then parse_array
    when /[0-9\-]/ then parse_number_as_string
    when 't', 'f', 'n' then parse_literal_as_string
    else raise JSON::ParserError, "Unexpected char at #{@index}"
    end
  end

  def parse_string
    @index += 1
    start = @index
    while @index < @source.length && @source[@index] != '"'
      @index += 1 if @source[@index] == '\\'
      @index += 1
    end
    str = @source[start...@index].gsub(/\\(["\\\/bfnrt])/) do
      case $1
      when 'b' then "\b"; when 'f' then "\f"; when 'n' then "\n"
      when 'r' then "\r"; when 't' then "\t"; else $1
      end
    end
    @index += 1
    str
  end

  def parse_number_as_string
    start = @index
    while @index < @source.length && @source[@index] =~ /[0-9.eE+\-]/
      @index += 1
    end
    @source[start...@index]
  end

  def parse_literal_as_string
    if @source.start_with?('true', @index)
      @index +=4; 'true'
    elsif @source.start_with?('false', @index)
      @index +=5; 'false'
    elsif @source.start_with?('null', @index)
      @index +=4; 'null'
    else
      raise JSON::ParserError, "Unexpected literal at #{@index}"
    end
  end

  def parse_object
    @index +=1
    obj = {}
    skip_whitespace
    while @index < @source.length && @source[@index] != '}'
      key = parse_string
      skip_whitespace
      raise JSON::ParserError, "Missing colon at #{@index}" unless @source[@index] == ':'
      @index +=1
      obj[key] = parse_value
      skip_whitespace
      @index +=1 if @source[@index] == ','
    end
    @index +=1
    obj
  end

  def parse_array
    @index +=1
    arr = []
    skip_whitespace
    while @index < @source.length && @source[@index] != ']'
      arr << parse_value
      skip_whitespace
      @index +=1 if @source[@index] == ','
    end
    @index +=1
    arr
  end
end

# 使用示例
raw_json = '{"user_id": 1234567890123456789, "balance": 0.00000001, "is_active": true, "deleted_at": null}'
parser = RawJSONParser.new
parsed_data = parser.parse(raw_json)
puts parsed_data.inspect
# 输出: {"user_id"=>"1234567890123456789", "balance"=>"0.00000001", "is_active"=>"true", "deleted_at"=>"null"}

这个解析器完全复刻原始JSON的字符内容,不会把数字转成Float/BigDecimal,也不会把布尔/null转成Ruby对应类型,完美满足格式迁移的需求。

方案2:用json-schema库的RawParser(现成工具)

如果不想自己写解析器,可以用json-schema gem提供的RawParser,它专门做"无类型转换"的解析,把所有非结构值都保留为原始字符串:

# 先安装gem:gem install json-schema
require 'json-schema'

raw_json = '{"order_no": 9876543210987654321, "discount": 15.5}'
parser = JSON::Schema::RawParser.new
parsed_data = parser.parse(raw_json)
puts parsed_data.inspect
# 输出: {"order_no"=>"9876543210987654321", "discount"=>"15.5"}

这个方案更省心,不需要维护自定义解析器,适合快速开发场景。

注意事项

不管用哪种方案,后续输出JSON时要注意:如果直接用JSON.generate,会把字符串值加上双引号输出(比如把"123"变成"\"123\"")。如果要还原原始格式,需要自己实现序列化逻辑,遍历哈希/数组时,根据原始值的类型(比如判断是否是数字字符串、布尔字符串)来决定输出格式,或者直接复用解析时的原始片段。

内容的提问来源于stack exchange,提问作者Don Reba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 21:22:25