讲师中心 微信公众号
AI工具推荐 视频效率加速

Python处理CSV文件列数不一致及编码错误的教程

小丽君_2945

小丽君_2945

发布时间:2025-11-17 14:13:19

|

777人浏览过

|

来源于php中文网

原创

Python处理CSV文件列数不一致及编码错误的教程

本教程旨在解决大型csv文件中常见的列数不一致和字符编码问题。我们将使用python的`csv`模块,介绍两种有效策略:首先,精确识别并报告每条列数不符的行及其详细信息;其次,针对海量数据,提供一种将连续异常行聚合成范围进行报告的方法。通过这些技术,用户能够高效地定位并理解数据质量问题,为后续的数据清洗和导入工作奠定基础,同时避免常见的`unicodedecodeerror`。

引言:CSV数据质量挑战

在数据处理和导入(例如将Excel数据导入Teradata等数据库)过程中,CSV文件因其简洁性而被广泛使用。然而,原始CSV数据往往存在各种“脏”数据问题,尤其是在手动输入或缺乏严格数据验证的场景下。其中最常见的挑战包括:

  1. 列数不一致:部分行包含的列数多于或少于预期,这会导致数据解析错误和导入失败。
  2. 字符编码问题:文件编码与读取编码不匹配时,可能出现乱码,甚至引发UnicodeDecodeError,导致程序中断。

对于包含数十万行、数十甚至上百列的大型CSV文件,手动检查和修复是不可行的。本教程将展示如何利用Python及其强大的csv模块,高效地识别并报告这些数据质量问题。

方法一:识别并报告单个异常行

处理列数不一致问题的第一步是准确识别哪些行存在问题。相比于简单地统计逗号数量,使用Python内置的csv模块是更健壮的方法,因为它能够正确处理包含逗号的引用字段以及嵌入的换行符。

核心思路

  1. 设定期望列数:明确CSV文件应该包含多少列。
  2. 逐行读取:使用csv.reader迭代器逐行读取数据。
  3. 比较列数:对于每一行,检查其解析后的列数是否与期望值一致。
  4. 记录异常:如果列数不符,则记录该行的行号和实际列数。

示例代码

以下代码演示了如何生成一个报告,列出所有列数不符合预期(例如,期望66列)的行及其对应的实际列数。

kashen-mysql DDLtoExcel
kashen-mysql DDLtoExcel

解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。

下载

立即学习“Python免费学习笔记(深入)”;

import csv

# 设定期望的列数,根据实际情况修改
EXPECTED_COLS = 66 
INPUT_FILE = 'Data.csv'
OUTPUT_FILE_FLAT = 'output_anomalous_rows.csv'

def report_single_anomalies(input_csv_path, output_report_path, expected_columns):
    """
    识别并报告CSV文件中列数不一致的单个行。

    Args:
        input_csv_path (str): 输入CSV文件的路径。
        output_report_path (str): 输出报告CSV文件的路径。
        expected_columns (int): CSV文件期望的列数。
    """
    print(f"开始分析文件: {input_csv_path}")
    print(f"期望列数: {expected_columns}")

    try:
        with open(output_report_path, 'w', newline='', encoding='utf-8') as f_out:
            writer = csv.writer(f_out)
            writer.writerow(["行号", "实际列数"]) # 写入报告头

            # 推荐使用 'utf-8' 编码,如果遇到 UnicodeDecodeError,可尝试 'latin-1' 或 'gbk'
            with open(input_csv_path, 'r', newline='', encoding='utf-8') as f_in:
                reader = csv.reader(f_in)

                # 跳过CSV文件的标题行(如果存在)
                try:
                    header = next(reader)
                    # 如果需要,可以在这里检查标题行的列数
                    print(f"已跳过标题行: {header}")
                except StopIteration:
                    print("文件为空或不含数据。")
                    return

                # 使用enumerate从1开始计数,对应文件中的行号
                for i, row in enumerate(reader, start=1):
                    actual_cols = len(row)
                    if actual_cols != expected_columns:
                        writer.writerow([i, actual_cols])
                        print(f"发现异常行 - 行号: {i}, 实际列数: {actual_cols}")
        print(f"异常行报告已生成至: {output_report_path}")

    except FileNotFoundError:
        print(f"错误:文件 '{input_csv_path}' 未找到。")
    except UnicodeDecodeError as e:
        print(f"字符编码错误:{e}。请尝试更改文件编码参数,例如 'latin-1' 或 'gbk'。")
    except Exception as e:
        print(f"发生未知错误:{e}")

# 调用函数进行分析
report_single_anomalies(INPUT_FILE, OUTPUT_FILE_FLAT, EXPECTED_COLS)

代码解析

  • import csv: 导入Python的csv模块,这是处理CSV文件的标准库。
  • EXPECTED_COLS = 66: 定义一个常量来存储期望的列数。请根据您的实际数据调整此值。
  • with open(..., newline='', encoding='utf-8'):
    • newline='':这是csv模块推荐的最佳实践,可以防止在Windows系统上写入时出现额外的空行,并正确处理包含换行符的字段。
    • encoding='utf-8':这是解决UnicodeDecodeError的关键。指定正确的字符编码至关重要。如果utf-8不起作用,您的文件可能使用了其他编码,例如latin-1、gbk或cp1252。请根据文件实际编码进行尝试。
  • writer = csv.writer(f_out): 创建一个csv.writer对象,用于将异常信息写入报告文件。
  • reader = csv.reader(f_in): 创建一个csv.reader对象,它将CSV文件视为一个迭代器,每次迭代返回一行数据(作为一个列表)。
  • next(reader): 用于跳过CSV文件的标题行。如果您的CSV文件没有标题行,请删除此行。
  • for i, row in enumerate(reader, start=1):
    • enumerate函数在迭代reader时提供一个计数器i,start=1确保行号从1开始,与大多数文件编辑器中的行号一致。
    • row变量是一个列表,其中包含了当前行的所有字段。
  • len(row): 获取当前行的实际列数。
  • if actual_cols != expected_columns:: 条件判断,如果实际列数与期望列数不符,则将其写入报告文件。

方法二:聚合异常行范围报告

对于拥有数十万行甚至更多数据的大型CSV文件,如果异常行非常多,生成一个包含每一条异常行的报告可能会非常庞大且难以阅读。在这种情况下,将连续的、具有相同异常列数的行聚合成一个范围进行报告,会更加高效和实用。

核心思路

  1. 跟踪状态:维护一个状态变量,记录当前是否正在跟踪一个异常行范围,以及该范围的起始行号和列数。
  2. 状态切换:当遇到列数与前一行不同,或者从异常状态切换到正常状态时,结束当前范围的记录并写入报告。
  3. 聚合报告:将连续的具有相同异常列数的行合并为“起始行 - 结束行”的格式。

示例代码

import csv

# 设定期望的列数,根据实际情况修改
EXPECTED_COLS = 66
INPUT_FILE = 'Data.csv'
OUTPUT_FILE_RANGES = 'output_anomalous_ranges.csv'

def write_report_row(writer, cols_ct, row_start, row_end):
    """
    将异常行范围写入报告文件。
    如果起始行和结束行相同,则只写入起始行。
    """
    if row_start == row_end:
        writer.writerow([cols_ct, row_start, ""]) # 单行异常,结束行留空
    else:
        writer.writerow([cols_ct, row_start, row_end])

def report_anomalous_ranges(input_csv_path, output_report_path, expected_columns):
    """
    识别并报告CSV文件中列数不一致的行范围。

    Args:
        input_csv_path (str): 输入CSV文件的路径。
        output_report_path (str): 输出报告CSV文件的路径。
        expected_columns (int): CSV文件期望的列数。
    """
    print(f"开始分析文件 (范围报告): {input_csv_path}")
    print(f"期望列数: {expected_columns}")

    # 定义追踪状态常量
    NO_TRACK = -1 

    try:
        with open(output_report_path, 'w', newline='', encoding='utf-8') as f_out:
            writer = csv.writer(f_out)
            writer.writerow(["实际列数", "起始行", "结束行"]) # 写入报告头

            with open(input_csv_path, 'r', newline='', encoding='utf-8') as f_in:
                reader = csv.reader(f_in)

                # 处理标题行
                try:
                    header = next(reader)
                    # 可以在这里根据标题行确定期望列数,或检查其列数
                    print(f"已跳过标题行: {header}")
                except StopIteration:
                    print("文件为空或不含数据。")
                    return

                # 初始化追踪变量
                tracking = False # 是否正在追踪一个异常范围
                row_num_start = NO_TRACK # 当前异常范围的起始行号
                cols_count_in_range = NO_TRACK # 当前异常范围的列数

                last_processed_row_index = 0 # 记录循环中最后处理的行索引 (用于最终flush)

                for i, row in enumerate(reader, start=1):
                    last_processed_row_index = i # 更新最后处理的行索引
                    current_cols = len(row)

                    # 如果当前行的列数与当前追踪的列数不同
                    if current_cols != cols_count_in_range:
                        # 如果正在追踪一个范围,则结束它并写入报告
                        if tracking:
                            write_report_row(writer, cols_count_in_range, row_num_start, i - 1) # i-1 是前一行

                        # 判断当前行是否为异常行
                        if current_cols == expected_columns:
                            # 当前行正常,停止追踪
                            tracking = False
                            row_num_start = NO_TRACK
                            cols_count_in_range = NO_TRACK
                        else:
                            # 当前行异常,开始新的追踪
                            tracking = True
                            row_num_start = i
                            cols_count_in_range = current_cols
                    # 如果当前行的列数与当前追踪的列数相同,则继续追踪,无需操作

                # 循环结束后,如果还在追踪一个范围,需要将其写入报告
                if tracking:
                    write_report_row(writer, cols_count_in_range, row_num_start, last_processed_row_index)
        print(f"异常行范围报告已生成至: {output_report_path}")

    except FileNotFoundError:
        print(f"错误:文件 '{input_csv_path}' 未找到。")
    except UnicodeDecodeError as e:
        print(f"字符编码错误:{e}。请尝试更改文件编码参数,例如 'latin-1' 或 'gbk'。")
    except Exception as e:
        print(f"发生未知错误:{e}")

# 调用函数进行分析
report_anomalous_ranges(INPUT_FILE, OUTPUT_FILE_RANGES, EXPECTED_COLS)

代码解析

  • write_report_row 函数: 这是一个辅助函数,用于格式化写入报告行。它会判断一个范围是单行还是多行,并相应地调整输出。
  • tracking, row_num_start, cols_count_in_range: 这三个变量是状态机核心。
    • tracking:布尔值,表示当前是否正在记录一个异常行范围。
    • row_num_start:当前被追踪的异常范围的起始行号。
    • cols_count_in_range:当前被追踪的异常范围中所有行的列数。
  • if current_cols != cols_count_in_range:: 这是状态切换的主要逻辑。当遇到一个列数与当前追踪的范围不同(或开始新的追踪)的行时,会触发处理。
    • 如果tracking为True,说明之前的范围结束了,调用write_report_row写入报告。
    • 然后根据current_cols是否等于expected_columns来决定是停止追踪(当前行正常)还是开始新的追踪(当前行异常)。
  • 循环结束后的if tracking:: 循环结束后,如果最后一个范围是异常的且正在被追踪,需要额外调用write_report_row来将其写入报告。

关键注意事项与最佳实践

  1. 文件编码处理:
    • UnicodeDecodeError是处理文本文件时常见的错误。务必在open()函数中明确指定encoding参数。
    • encoding='utf-8'是现代Web和大多数系统推荐的通用编码。
    • 如果utf-8失败,常见的替代编码包括latin-1 (ISO-8859-1的超集,能表示256个字符,不会报错但可能乱码)、gbk (简体中文编码)、cp1252 (Windows默认编码)。您可能需要根据文件来源尝试不同的编码。
    • 对于不确定编码的文件,可以使用chardet等库进行编码检测。
  2. csv模块与手动计数比较:
    • 不要使用line.count(',')来判断列数。这种方法无法正确处理包含逗号的引用字段(例如"City, State")或字段内部的换行符。
    • csv模块是专门为CSV格式设计的,能够正确解析这些复杂情况。
  3. 数据清洗策略:识别与修复分离:
    • 本教程提供的是识别和报告异常行的工具。直接在读取过程中“当场修复”通常非常复杂且容易出错。
    • 推荐的工作流程是:首先使用这些脚本生成详细的异常报告,然后根据报告手动或通过另一个专门的脚本进行数据清洗和转换,最后再进行导入。
  4. 可扩展性与性能:
    • 上述两种方法都采用逐行处理的方式,避免一次性将整个大文件加载到内存中,因此对于百万级别甚至千万级别的行数都具有良好的可扩展性。
    • Python的csv模块本身是C语言实现的,性能较高。

总结

通过本教程,您学习了如何使用Python的csv模块高效地识别CSV文件中的数据质量问题,特别是列数不一致和字符编码错误。我们提供了两种报告策略:针对小型数据集的单个异常行报告,以及针对大型数据集的聚合异常行范围报告。这些工具能够帮助您在数据导入前,清晰地了解数据质量状况,为后续的数据清洗和转换工作提供精确的指引,从而确保数据导入的顺利进行和数据质量的可靠性。记住,数据清洗是一个迭代的过程,从识别到修复,每一步都至关重要。

热门AI工具

更多
码上飞
码上飞 Hot

一款基于自然语言的AI应用开发平台,可根据用户描述自动生成应用程序,帮助个人和团队快速完成应用原型与开发。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

6284

2023.10.24

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3668

2023.11.20

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

3399

2023.07.26

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2958

2023.07.27

windows照片无法显示
windows照片无法显示

当我们尝试打开一张图片时,可能会出现一个错误提示,提示说"Windows照片查看器无法显示此图片,因为计算机上的可用内存不足",本专题为大家提供windows照片无法显示相关的文章,帮助大家解决该问题。

1528

2023.08.01

windows查看端口被占用的情况
windows查看端口被占用的情况

windows查看端口被占用的情况的方法:1、使用Windows自带的资源监视器;2、使用命令提示符查看端口信息;3、使用任务管理器查看占用端口的进程。本专题为大家提供windows查看端口被占用的情况的相关的文章、下载、课程内容,供大家免费下载体验。

2679

2023.08.02

windows无法访问共享电脑
windows无法访问共享电脑

在现代社会中,共享电脑是办公室和家庭的重要组成部分。然而,有时我们可能会遇到Windows无法访问共享电脑的问题。这个问题可能会导致数据无法共享,影响工作和生活的正常进行。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

3350

2023.08.08

windows自动更新
windows自动更新

Windows操作系统的自动更新功能可以确保系统及时获取最新的补丁和安全更新,以提高系统的稳定性和安全性。然而,有时候我们可能希望暂时或永久地关闭Windows的自动更新功能。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1697

2023.08.10

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

0

2026.11.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Excel 教程
Excel 教程

共162课时 | 45.2万人学习

成为PHP架构师-自制PHP框架
成为PHP架构师-自制PHP框架

共28课时 | 3.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn