Ruby中如何从user_location字段字符串提取lat、lon(正则或优解)
Ruby 提取user_location中的经纬度
背景
数据库user_location列原设计存储标准JSON格式数据,正常示例为{"lon":74.46586,"lat":31.523199},但实际取出的字符串为Ruby Hash的inspect格式,示例为"{\"lon\"=>74.43935992994889, \"lat\"=>31.52203286189515}"。
现有提取逻辑依赖split拆分,鲁棒性差,需要更规范的实现方案。
现有实现
当前用到的提取代码:
lon = @session_request.user_location.split(',').first.split('=>').last.chomp('}').to_f lat = @session_request.user_location.split(',').last.split('=>').last.chomp('}').to_f
Pry控制台验证结果:
- 执行
location = @session_request.user_location,返回:=> "{\"lon\"=>74.43935992994889, \"lat\"=>31.52203286189515}" - 执行提取lon的逻辑,返回:
=> "74.43935992994889" - 执行提取lat的逻辑,返回:
=> "31.52203286189515"
该方案依赖键的固定顺序,一旦键顺序调整、数值格式变化(如负数、科学计数法)就会出错,鲁棒性极差。
优化方案
1. 转标准JSON后解析(优先推荐)
现有字符串仅将标准JSON的键值分隔符:替换为了Ruby风格的=>,可以先替换分隔符再按标准JSON解析,安全且不依赖键顺序:
require 'json' # 容错处理空值/解析失败的情况,与原逻辑行为兼容 location_str = @session_request.user_location.to_s location_data = JSON.parse(location_str.gsub(/=>/, ':')) rescue {} lon = location_data['lon'].to_f lat = location_data['lat'].to_f
注意:不要直接使用
eval解析该字符串,即使输入来自内部数据库,也存在潜在的代码注入风险。
2. 正则提取(轻量场景适用)
如果不需要完整解析整个结构,可直接用正则匹配指定键对应的数值,兼容正负值、科学计数法、多余空格等情况:
location_str = @session_request.user_location.to_s # 匹配lon对应的数值,匹配不到默认返回0.0 lon = location_str.match(/"lon"\s*=>\s*(-?\d+\.?\d*(?:e[+-]?\d+)?)/i)&.[](1)&.to_f || 0.0 # 匹配lat对应的数值,匹配不到默认返回0.0 lat = location_str.match(/"lat"\s*=>\s*(-?\d+\.?\d*(?:e[+-]?\d+)?)/i)&.[](1)&.to_f || 0.0
3. 根源优化(长期方案)
当前字符串格式问题本质是写入时未做标准JSON序列化,长期可调整写入逻辑:
- 写入数据时,不要直接用Hash的
to_s方法转字符串,改用to_json生成标准JSON后再存储 - 如果使用Rails框架,可直接将数据库列类型修改为
json/jsonb,框架会自动完成序列化与反序列化,无需手动解析字符串。
内容的提问来源于stack exchange,提问作者Wasif Ali
相关产品推荐
相关产品推荐

