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
相关产品推荐
相关产品推荐

