← 中文资源

简体中文版本

识别 CSV 分隔符并读取行

从样本中自动识别 CSV 的分隔符与引号风格,再解析为字典行,避免把逗号硬编码进解析逻辑。

阅读英文原文

功能说明

用户上传的 CSV 很少完全统一:欧洲地区常用分号,日志导出可能用制表符,某些系统用竖线。直接按逗号切分会把整行当成一个字段。Python 标准库的 csv.Sniffer 会统计候选分隔符在样本中的出现规律,结合引号与转义特征推断方言。本例把推断结果整理成字典,并用同一个方言交给 DictReader 解析,使表头自动成为每行的键。

函数只依赖标准库,适合命令行工具、数据导入脚本和测试夹具。返回字典而不是 csv.Dialect 对象,便于打印、记录日志或在配置中复用。

关键代码

detect_dialect 调用 Sniffer().sniff,并把候选分隔符限制为逗号、分号、制表符和竖线,避免把普通文本中的字母误判为分隔符。返回的 dialect 对象提供 delimiter、quotechar、doublequote 和 skipinitialspace 四项。read_rows 再次推断方言后创建 DictReader,用 StringIO 包装字符串,最后把每一行转成普通字典,方便 JSON 序列化。main 用分号样本验证识别结果。

使用注意

Sniffer 需要足够多的样本才能可靠判断,只有一行数据时可能猜错,传入前几行即可。空文件或字段极少的内容会抛出 csv.Error,应捕获后回退到默认方言。推断只覆盖分隔符与引号,不处理编码、换行符和千位分隔。DictReader 遇到重复表头会覆盖前面的列,读取后应校验列名唯一性。自动识别不应替代用户显式指定方言,生产导入界面最好允许手动覆盖。

验证方式

运行脚本,方言字典应显示 delimiter 为分号、quotechar 为双引号,skipinitialspace 为 False。行列表包含两条记录,字段为 name、role、city,第二条城市为 New York,证明分号被正确切分。可把样本改成制表符分隔,确认 delimiter 跟随变化。

代码示例

import csv
import io


def detect_dialect(sample: str) -> dict[str, object]:
    dialect = csv.Sniffer().sniff(sample, delimiters=",;\t|")
    return {
        "delimiter": dialect.delimiter,
        "quotechar": dialect.quotechar,
        "doublequote": dialect.doublequote,
        "skipinitialspace": dialect.skipinitialspace,
    }


def read_rows(text: str) -> list[dict[str, str]]:
    dialect = csv.Sniffer().sniff(text, delimiters=",;\t|")
    reader = csv.DictReader(io.StringIO(text), dialect=dialect)
    return [dict(row) for row in reader]


if __name__ == "__main__":
    sample = "name;role;city\nAda;engineer;London\nGrace;admiral;New York\n"
    print(detect_dialect(sample))
    print(read_rows(sample))