0

0

Python csv.writer 写入数据时额外引号问题的解析与解决方案

DDD

DDD

发布时间:2025-07-09 16:30:12

|

530人浏览过

|

来源于php中文网

原创

python csv.writer 写入数据时额外引号问题的解析与解决方案

本文旨在解决使用 Python csv 模块的 csv.writer 写入数据时,因数据源结构不当导致输出字段被额外引号包裹的问题。当从数据库(如 MySQL)获取的数据集每行是一个包含预先逗号分隔字符串的单元素元组时,csv.writer 会将其视为单个字段并添加引号。教程将详细分析问题成因,并提供通过字符串 split() 方法预处理数据流的有效解决方案,确保 CSV 文件内容符合预期格式。

问题描述与根源分析

在使用 Python 的 csv 模块向 CSV 文件写入数据时,一个常见的问题是,即使我们希望数据以 item1,item2,item3 的形式呈现,最终输出却变成了 "item1,item2,item3",即整个字段被额外的一对双引号包裹。这通常发生在数据源的结构与 csv.writer 的预期不符时。

考虑以下典型场景:从数据库(如 MySQL)查询数据,并使用 cursor.fetchall() 获取结果集。如果数据库查询结果的每一行被设计为包含一个已经由逗号分隔的字符串,例如:

# 假设从数据库获取的 result_set 结构如下:
result_set = [
    ('item1,item2,item3',),
    ('item4,item5,item6',)
]

在这种情况下,result_set 中的每个元素都是一个单元素元组 ('...'),而这个元组内部的字符串 ('item1,item2,item3') 已经包含了我们期望的多个字段。

当我们尝试使用 csv.writer.writerows() 方法直接写入这样的 result_set 时,csv.writer 的默认行为是将每个元组视为一行,并将元组中的每个元素视为一个独立的字段。因此,当它遇到 ('item1,item2,item3',) 时,它会将其内部的 'item1,item2,item3' 视为一个完整的字符串字段。根据 CSV 规范,如果一个字段内部包含逗号(或其他分隔符),或者包含换行符、引号等特殊字符,csv.writer 会自动用双引号将其包裹起来,以确保数据的完整性和正确解析。这就是导致 "item1,item2,item3" 出现的原因。

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

以下是导致此问题的典型代码示例:

import csv

# 模拟从数据库获取的数据集
# 注意:每个元组只包含一个元素,而这个元素本身是逗号分隔的字符串
result_set = [
    ('item1,item2,item3',),
    ('item4,item5,item6',)
]

filename = 'output_quoted.csv'
try:
    with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
        datafile = csv.writer(csvfile)
        datafile.writerows(result_set)
    print(f"数据已写入 {filename},请检查内容。")
except Exception as e:
    print(f"写入文件时发生错误: {e}")

# output_quoted.csv 的内容将是:
# "item1,item2,item3"
# "item4,item5,item6"

解决方案:数据预处理

解决这个问题的核心思想是:在将数据传递给 csv.writer 之前,对其进行预处理,确保每一行都是一个包含独立字段的列表或元组,而不是一个包含逗号分隔字符串的单元素元组。最直接的方法是使用字符串的 split(',') 方法。

PpcyAI
PpcyAI

泡泡次元AI-游戏美术AI创作平台,低门槛上手,高度可控,让你的创意秒速落地

下载

由于 result_set 的结构是 [('value1,value2',), ('value3,value4',)],我们可以遍历 result_set,对于每个单元素元组 (col,),取出其内部的字符串 col,然后使用 col.split(',') 将其拆分成一个字段列表。

import csv

# 模拟从数据库获取的数据集
result_set = [
    ('item1,item2,item3',),
    ('item4,item5,item6',),
    ('item7,item8,item9,item10',) # 示例包含不同数量的字段
]

filename = 'output_unquoted.csv'
try:
    with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
        datafile = csv.writer(csvfile)

        # 关键的预处理步骤:使用生成器表达式
        # 对于 result_set 中的每个 (col,) 元组,取出 col 并用逗号分割
        processed_data = (col.split(",") for (col,) in result_set)

        datafile.writerows(processed_data)
    print(f"数据已写入 {filename},请检查内容。")
except Exception as e:
    print(f"写入文件时发生错误: {e}")

# output_unquoted.csv 的内容将是:
# item1,item2,item3
# item4,item5,item6
# item7,item8,item9,item10

代码示例与详解

在上述解决方案中,核心在于这一行:

processed_data = (col.split(",") for (col,) in result_set)

这是一个生成器表达式,它做了以下几件事:

  1. (col,) in result_set: 遍历 result_set 中的每个元素。由于 result_set 中的每个元素都是一个单元素元组(例如 ('item1,item2,item3',)),我们使用 (col,) 进行元组解包,直接将元组内部的字符串赋值给变量 col。
  2. col.split(","): 对获取到的 col 字符串执行 split(",") 操作。这将把字符串按照逗号分割成一个列表。例如,'item1,item2,item3'.split(',') 会得到 ['item1', 'item2', 'item3']。
  3. ( ... for ... in ... ): 这是一个生成器表达式,它不会立即创建整个列表,而是按需生成每个处理后的行数据。这对于处理大型数据集非常高效,因为它避免了一次性将所有处理后的数据加载到内存中。

当 datafile.writerows(processed_data) 被调用时,csv.writer 会从 processed_data 生成器中逐一获取处理后的行数据(即形如 ['item1', 'item2', 'item3'] 的列表),然后将列表中的每个元素作为独立的字段写入 CSV 文件,并正确地用逗号分隔,而不会再额外添加双引号,除非字段本身包含特殊字符(如逗号、双引号或换行符)且 quoting 参数设置为 csv.QUOTE_MINIMAL(这是默认行为)。

注意事项与最佳实践

  1. 数据源结构确认: 在处理从数据库或其他外部源获取的数据时,务必清楚其返回的数据结构。理解 cursor.fetchall() 返回的是一个元组的列表,其中每个元组代表一行,而元组内部的元素才是字段。如果你的查询本身就将多个字段合并成一个字符串返回,那么这种预处理是必要的。理想情况下,数据库查询应该返回多个独立的字段,而不是一个合并的字符串。 例如,如果数据库查询返回的是 [('item1', 'item2', 'item3'), ('item4', 'item5', 'item6')] 这样的结构,那么就不需要 split() 操作,可以直接使用 writerows() 写入。
  2. csv.writer 的 quoting 参数: csv.writer 提供了 quoting 参数来控制字段的引用行为:
    • csv.QUOTE_MINIMAL (默认):仅当字段包含 delimiter、quotechar 或 lineterminator 时才引用。
    • csv.QUOTE_ALL:引用所有字段。
    • csv.QUOTE_NONNUMERIC:引用所有非数字字段。
    • csv.QUOTE_NONE:不引用任何字段。如果字段包含特殊字符,这可能导致输出的 CSV 文件格式错误。 在本次问题中,默认的 QUOTE_MINIMAL 行为正是导致问题的原因,因为它将 item1,item2,item3 视为一个需要被引用的包含逗号的字段。
  3. 数据清洗与错误处理: 在使用 split() 方法时,需要考虑以下情况:
    • 空字符串: 如果原始字符串中存在连续的逗号(如 ",item2,item3" 或 item1,,item3),split(',') 会生成空字符串。确保你的下游系统能够正确处理这些空字段。
    • 空白字符: 如果原始字符串中的字段前后有空格(如 " item1 , item2 "),split(',') 之后这些空格会保留。如果需要去除,可以在 split() 后对每个字段进行 strip() 操作,例如 (field.strip() for field in col.split(","))。
    • 分隔符冲突: 确保用于 split() 的分隔符 (',') 不会在字段本身的有效内容中出现,否则会导致不正确的分割。如果字段内容可能包含逗号,则需要重新考虑数据结构或使用更复杂的解析逻辑。

总结

当 Python csv.writer 意外地在写入的字段周围添加额外引号时,通常是因为数据源提供的每一行数据被 csv.writer 错误地解释为包含一个已经预格式化为逗号分隔字符串的“单个字段”。解决此问题的关键在于,在将数据传递给 writerows() 方法之前,对数据进行预处理。通过使用字符串的 split() 方法,将包含多个值的单个字符串拆分成独立的字段列表,可以确保 csv.writer 按照预期将每个字段正确地写入 CSV 文件,避免不必要的引号包裹,从而生成符合标准且易于解析的 CSV 文件。理解数据结构和 csv.writer 的工作原理是避免此类问题的关键。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

668

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

247

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

281

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

516

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

256

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

387

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

533

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

603

2023.08.14

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

8

2026.01.30

热门下载

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

精品课程

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

共48课时 | 2万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 815人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号