将 SQL 查询结果字符串解析为对象数组的完整教程

1次阅读

将 SQL 查询结果字符串解析为对象数组的完整教程

本文详解如何将格式化的 sql 查询输出字符串(含表头与多行数据)高效转换为结构化字典列表,兼容 python 2 与 python 3,并支持空格分隔的字段解析及常见边界情况处理。

本文详解如何将格式化的 sql 查询输出字符串(含表头与多行数据)高效转换为结构化字典列表,兼容 python 2 与 python 3,并支持空格分隔的字段解析及常见边界情况处理。

在实际数据处理中,尤其是与遗留数据库交互或调用 CLI 工具执行 SQL 时,常会得到纯文本格式的查询结果(如 psql -t 或某些 ORM 的原始输出),其结构类似:

enable id  ============= f   avc-qwqwq t abd-rrtrtr  f rec-yyuyu

该文本包含表头行、分隔线(============)和若干数据行。目标是将其转化为标准的结构化对象数组(即 Python 中的 list[dict]),例如:

[   {'enable': 'f', 'id': 'avc-qwqwq'},   {'enable': 't', 'id': 'abd-rrtrtr'},   {'enable': 'f', 'id': 'rec-yyuyu'} ]

✅ 核心思路:分步解析 + 动态映射

  1. 按行切分:使用 str.splitlines() 安全处理跨平台换行符(n, rn),避免 split(‘n’) 在末尾空行或 windows 环境下的潜在问题;
  2. 提取表头:跳过分隔线(第二行),取首行并用 str.split() 拆分为字段名(自动忽略多余空白);
  3. 逐行构建对象:对每条数据行,同样用 split() 提取非空字段,再通过 zip(header, values) 与 dict() 动态构造键值对。

? 推荐实现(Python 3 原生简洁版)

text = '''enable id  ============= f   avc-qwqwq t abd-rrtrtr  f rec-yyuyu'''  # 步骤1:安全按行分割(自动过滤空行 & 兼容换行符) lines = [line.strip() for line in text.splitlines() if line.strip()]  # 步骤2:提取表头(第一行),忽略分隔线(第二行起非空行即为数据) header = lines[0].split() data_rows = lines[2:]  # 跳过 header + separator  # 步骤3:逐行解析 → 构建字典列表 result = [] for row in data_rows:     values = row.split()  # 按任意空白分割,鲁棒性强     if len(values) >= len(header):  # 防止字段数不匹配         obj = dict(zip(header, values[:len(header)]))         result.append(obj)  print(result) # 输出: # [{'enable': 'f', 'id': 'avc-qwqwq'}, {'enable': 't', 'id': 'abd-rrtrtr'}, {'enable': 'f', 'id': 'rec-yyuyu'}]

⚙️ Python 2 兼容写法(无解包语法)

Python 2 不支持 a, b, *rest = … 解包,改用迭代器显式消费:

text = '''enable id  ============= f   avc-qwqwq t abd-rrtrtr  f rec-yyuyu'''  lines_iter = iter(text.splitlines()) header_line = next(lines_iter).strip() _ = next(lines_iter)  # 跳过分隔线 data_lines = [line.strip() for line in lines_iter if line.strip()]  header = header_line.split() result = [     dict(zip(header, row.split()))      for row in data_lines      if row.split()  # 过滤空行 ]  print(result)

⚠️ 注意事项与健壮性增强

  • 字段对齐风险:若原始数据含空格但非分隔符(如 org 字段值为 “abc def”),split() 会错误切分。此时需改用固定列宽解析或正则提取:

    import re # 假设 header 位置已知:'enable' 占前2字符,'id' 从第4列起 pattern = r'^(S{1,2})s+(S.*)$' for row in data_lines:     match = re.match(pattern, row)     if match:         enable, org = match.groups()         result.append({'enable': enable.strip(), 'id': org.strip()})
  • 大小写/空格标准化:建议对 header 和 values 统一 strip(),避免 ‘enable ‘ 与 ‘enable’ 键不一致;

  • 缺失字段兜底:可为 zip 补充默认值,避免 dict(zip(h, v)) 因长度不等报错:

    from itertools import zip_longest obj = dict(zip_longest(header, values, fillvalue=''))
  • 编码兼容性:若字符串含非 ASCII 字符(如中文字段),确保源码文件声明 # -*- coding: utf-8 -*-,并在 Python 2 中显式解码 text.decode(‘utf-8’)。

✅ 总结

该方案以最小依赖、最大兼容性完成「文本表格 → 对象数组」的转换:
? 利用 splitlines() + strip() 处理换行与空白,普适性强;
? split() 默认按任意空白分割,天然适应多空格对齐场景;
? zip(header, values) 实现动态字段映射,无需硬编码键名;
? 两版本代码均通过空行过滤、长度校验提升鲁棒性。
适用于日志解析、CLI 工具集成、轻量 etl 等典型场景。

text=ZqhQzanResources