Ruby CSV解析10100E02转为1010000.0的问题排查与解决
问题原因
你代码里设置了:converters => :all,这个选项会启用Ruby CSV库的所有内置转换器,其中包含的numeric转换器会自动识别符合标准科学计数法格式的字符串并转换为浮点数:
10100E02是标准科学计数法格式(数字部分 +E+ 整数指数),被解析为10100 * 10^2 = 1010000.010001000E不符合科学计数法规则(E后没有整数指数),无法被识别为数字,因此保留为原始字符串
解决方案
根据需求,有几种可行的解决方式:
方式1:禁用自动类型转换
如果不需要CSV库自动转换任何字段类型,直接移除:converters => :all选项,所有字段都会保留为原始字符串,之后可手动处理需要转换的字段:
def extract_from_csv(filepath) l={} CSV.foreach(filepath, :headers => true, :header_converters => :symbol) do |row| c0 = row.fields[0] c1 = row.fields[1] if(l[c0].nil?) l[c0] = Hash.new() end l[c0][c1] = Hash[row.headers[2..-1].zip(row.fields[2..-1])] print "#{c0}.#{c1}) #{l[c0][c1]}\n" end end
修改后输出:
1.14) {:m=>"10001000E", :i=>"10100E02", :r=>"1"}
方式2:自定义转换器(保留特定格式字符串)
如果需要部分字段自动转换为数字,但要保留10100E02这类格式的字符串,可以自定义转换器,仅转换纯整数/浮点数,排除带E的字段:
def extract_from_csv(filepath) custom_converter = lambda do |field| # 只转换纯数字(整数/浮点数),跳过包含E的字段 if field.match?(/^\d+(\.\d+)?$/) Float(field) rescue Integer(field) else field end end l={} CSV.foreach(filepath, :headers => true, :header_converters => :symbol, :converters => custom_converter) do |row| c0 = row.fields[0] c1 = row.fields[1] if(l[c0].nil?) l[c0] = Hash.new() end l[c0][c1] = Hash[row.headers[2..-1].zip(row.fields[2..-1])] print "#{c0}.#{c1}) #{l[c0][c1]}\n" end end
这种方式下,r字段的1会转为整数,m和i字段保留为字符串,输出:
1.14) {:m=>"10001000E", :i=>"10100E02", :r=>1}
方式3:指定仅转换特定类型
如果只需要转换整数,不需要处理浮点数和科学计数法,可使用:converters => :integer,仅纯整数字段会被转换,其他保留字符串:
def extract_from_csv(filepath) l={} CSV.foreach(filepath, :headers => true, :header_converters => :symbol, :converters => :integer) do |row| c0 = row.fields[0] c1 = row.fields[1] if(l[c0].nil?) l[c0] = Hash.new() end l[c0][c1] = Hash[row.headers[2..-1].zip(row.fields[2..-1])] print "#{c0}.#{c1}) #{l[c0][c1]}\n" end end
输出结果与方式2一致。
内容的提问来源于stack exchange,提问作者romi
相关产品推荐
相关产品推荐

