如何根据键路径查询JSON文件中指定键对应值所在的行号
可靠获取JSON文件指定键路径对应值行号的实现方案
原有方案的问题
你现有方案的核心缺陷是会丢弃原JSON文件的格式信息:将原JSON解析为哈希后再用JSON.pretty_generate重新输出,相当于用统一的美化规则重写了文件内容,和原文件的换行、排版完全无关,因此计算得到的行号和原文件不可能匹配。
可靠实现方案
建议使用流式JSON解析+路径追踪的方案,直接基于原文件的内容逐字符解析,实时记录当前行号和当前解析的键路径,匹配到目标路径时直接返回当前行号,完全不会改动原文件的格式。
实现步骤
- 引入轻量的流式JSON解析库
json-stream,它支持监听解析过程中的换行、键、值等各类事件 - 解析过程中维护两个变量:当前已解析的键路径、当前所在行号
- 每次解析到新的对象键时更新当前路径,和目标路径匹配后,下一个解析到的值所在的行号就是要找的结果
代码实现
首先安装依赖:gem install json-stream
具体代码如下:
require 'json/stream' def get_json_value_line(file_path, target_key_path) target_segments = target_key_path.split('.') current_path = [] current_line = 1 result_line = nil capture_next_value = false # 初始化流式解析器 parser = JSON::Stream::Parser.new # 遇到换行时更新行号 parser.on(:nl) { current_line += 1 } # 解析到对象键时更新当前路径 parser.on(:key) do |key| current_path << key # 路径匹配时标记需要捕获下一个值的行号 capture_next_value = current_path == target_segments end # 解析到值/对象开头/数组开头时,检查是否需要捕获行号 [:value, :object_start, :array_start].each do |event| parser.on(event) do if capture_next_value result_line = current_line throw :parse_finish # 找到结果直接提前终止解析 end end end # 解析完一个对象时弹出路径最后一位,维护路径正确性 parser.on(:object_end) { current_path.pop } # 开始解析原文件 catch(:parse_finish) do File.open(file_path, 'r') do |f| f.each_char { |char| parser << char } end end result_line end # 调用示例 puts get_json_value_line("你的JSON文件路径", "foo.bar2")
方案优势
- 完全基于原文件内容解析,不管原JSON是自定义缩进、数组同行还是其他任意格式,都能返回正确的行号
- 流式解析不需要加载整个JSON到内存,即使是GB级的大文件也能正常运行
- 当前版本已经适配你要求的不考虑数组跨多行的场景,后续需要支持数组路径时只要补充数组索引的路径维护逻辑即可
内容的提问来源于stack exchange,提问作者Bustikiller
相关产品推荐
相关产品推荐

