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

处理Pandas中带嵌入双引号的制表符分隔文件:实现精确读写回溯

夜伟小哥_1191

夜伟小哥_1191

发布时间:2025-11-15 12:59:10

|

325人浏览过

|

来源于php中文网

原创

处理pandas中带嵌入双引号的制表符分隔文件:实现精确读写回溯

在使用Pandas处理制表符分隔文件(TSV)时,我们经常会遇到一些非标准格式,其中一个常见且棘手的问题是字段值内部包含未转义的双引号,而整个字段又被双引号包裹。例如,一个字段可能是 `"Series 48SL–5 WEDGE–LOK, 2-56UNC-2B, 5.00", chem film, lock washer and flat"`,其中 `5.00"` 中的双引号并未被转义。标准的 `pd.read_csv` 方法在读取这类文件时,可能会错误地解析这些嵌入的引号,导致数据损坏;而 `df.to_csv` 在写回时,则可能以不同的方式转义,从而无法实现输入文件与输出文件的精确匹配。本教程将详细介绍如何有效解决这一挑战,确保数据在读取和写入过程中保持其原始格式的完整性。

理解问题:Pandas默认行为与非标准TSV

考虑以下制表符分隔数据示例 test.exp:

"HEADER"    "ID"    "Part Reference"    "Value" "Part_Description"
"PARTOCC:17306" "17306" "M1"    "48SL-5S-50-C-LF"   "Series 48SL–5 WEDGE–LOK, 2-56UNC-2B, 5.00", chem film, lock washer and flat"
"PARTOCC:17310" "17310" "M2"    "48SL-5S-50-C-LF"   "Series 48SL–5 WEDGE–LOK, 2-56UNC-2B, 5.00", chem film, lock washer and flat"
"PARTOCC:65494" "65494" "J4E"   "311P822-MC-095-BS-D"   "GSFC CPCI J3 RA MALE 95 Position 0.123" tails"

其中 Part_Description 字段的值,如 "Series 48SL–5 WEDGE–LOK, 2-56UNC-2B, 5.00", chem film, lock washer and flat",包含了一个未转义的嵌入双引号 5.00"。当我们尝试使用 pandas.read_csv 读取并立即使用 df.to_csv 写回时,会发现输出文件与输入文件不一致。例如,原始的 5.00", chem film... 可能会变成 5.00, chem film..."""。这是因为Pandas试图遵循标准的CSV/TSV转义规则,将嵌入的引号视为字段结束或需要双重转义,而这与原始文件的非标准格式冲突。

我们的目标是实现一个“读-写”回溯(roundtrip),即 check.exp 文件必须与 test.exp 文件完全一致。

解决方案一:使用Python csv 模块进行手动解析和处理

当文件格式不完全符合标准CSV/TSV规范,特别是当引用字符处理方式异常时,Python内置的 csv 模块提供了更底层的控制。通过设置 quoting=csv.QUOTE_NONE,我们可以指示解析器忽略引用规则,然后手动处理字段两端的引号。

此方法适用于以下情况:

  1. 确定每个字段都严格以双引号开始和结束。
  2. 字段内容中不包含制表符或换行符(如果包含,则需要更复杂的转义逻辑)。
import csv

def parse_non_standard_tsv(filepath: str) -> list[list[str]]:
    """
    使用csv模块解析非标准TSV文件,手动剥离字段两端的双引号。

    Args:
        filepath (str): TSV文件的路径。

    Returns:
        list[list[str]]: 解析后的数据,每行是一个字符串列表。
    """
    rows_data: list[list[str]] = []
    with open(filepath, newline="", encoding='utf-8') as f:
        # 使用QUOTE_NONE告诉csv模块不要处理引用,我们将手动处理
        reader = csv.reader(f, delimiter="	", quoting=csv.QUOTE_NONE)

        # 读取并处理头部
        header_raw = next(reader)
        # 剥离每个头部字段两端的双引号
        header = [x[1:-1] for x in header_raw]
        rows_data.append(header)

        # 读取并处理数据行
        for row_raw in reader:
            # 剥离每个数据字段两端的双引号
            processed_row = [x[1:-1] for x in row_raw]
            rows_data.append(processed_row)
    return rows_data

# 示例文件路径
exp_fn = r"test.exp"

# 解析文件
parsed_data = parse_non_standard_tsv(exp_fn)

# 打印解析后的数据(前几行)
for i, row in enumerate(parsed_data):
    if i < 5: # 打印前5行
        print(row)
    else:
        break

# 注意:如果需要将数据写回原始的“坏”格式,此方法需要额外的编码逻辑。
# 直接使用csv.writer写回,默认会尝试转义内部引号,可能无法匹配原始输入。
# 例如,如果内部字段包含引号,csv.writer会将其双重转义。
# 如果仅是解析并用于内部处理,此方法非常有效。

此方法能成功将数据解析为干净的字符串列表。然而,如果目标是精确地将数据写回原始的“坏”格式(即不进行任何转义,保留嵌入的引号),则需要更定制化的写入逻辑,因为 csv.writer 默认会尝试对包含特殊字符的字段进行引用和转义。

解决方案二:自定义解码与编码函数实现精确回溯

为了实现输入与输出文件的字节级精确匹配,我们需要完全控制解码和编码过程,绕过Pandas或 csv 模块的默认转义逻辑。这要求我们根据文件的具体“坏”格式来编写自定义的 decode 和 encode 函数。

Linux Journey
Linux Journey

当用户想学习Linux基础、命令行、文件系统等时,在LabEx查找并推荐免费的Linux Journey课程。

下载

此方法是实现“输入 == 输出”的最可靠方式。

import sys

# 定义文件格式常量
END = "
"  # 预期行结束符
DELIM = "	"  # 预期分隔符
QUOT = '"'  # 预期引用字符

Row = list[str] # 定义行类型

def decode(line: str) -> Row:
    """
    解码一个非标准编码的CSV/TSV行。
    确保行以END结尾,按DELIM分割行,并验证每个字段是否以QUOT开始和结束,
    然后剥离这些外部的QUOT。

    Args:
        line (str): 待解码的单行字符串。

    Returns:
        Row: 解码后的字段列表。

    Raises:
        ValueError: 如果行格式不符合预期。
    """
    if not line.endswith(END):
        raise ValueError(f"行不以 {repr(END)} 结尾")

    # 移除行结束符
    line = line[:-len(END)]
    fields = line.split(DELIM)

    for i, field in enumerate(fields):
        # 验证字段是否被引用字符包裹
        if not (field.startswith(QUOT) and field.endswith(QUOT)):
            raise ValueError(f"字段 {i} 未被 {repr(QUOT)} 包裹: {repr(field)}")

        # 剥离字段两端的引用字符
        fields[i] = field[1:-1]
    return fields

def encode(row: Row) -> str:
    """
    将一行字段编码回其原始的非标准格式。
    为每个字段添加引用字符,然后用分隔符连接,最后添加行结束符。

    Args:
        row (Row): 待编码的字段列表。

    Returns:
        str: 编码后的单行字符串。
    """
    # 为每个字段添加引用字符并用分隔符连接
    line = DELIM.join([f"{QUOT}{field}{QUOT}" for field in row])
    # 添加行结束符
    return line + END

def exit_err(msg: str):
    """打印错误信息并退出程序。"""
    print(msg, file=sys.stderr)
    sys.exit(1)

# 示例文件路径
input_fn = "test.exp"
output_fn = "check.exp"

rows_data: list[Row] = []
try:
    with open(input_fn, 'r', encoding='utf-8') as f_in:
        # 解码头部
        header_line = next(f_in)
        header = decode(header_line)
        rows_data.append(header) # 将头部也视为数据的一部分,方便后续统一处理

        # 解码数据行
        for i, line in enumerate(f_in):
            rows_data.append(decode(line))

    with open(output_fn, "w", encoding='utf-8') as f_out:
        # 编码并写入头部
        f_out.write(encode(rows_data[0])) # 写入第一个元素(头部)

        # 编码并写入数据行
        for row in rows_data[1:]: # 从第二个元素开始写入数据
            f_out.write(encode(row))

    print(f"文件 '{input_fn}' 已成功读入并以相同格式写回至 '{output_fn}'。")
    # 验证输入与输出是否完全一致(在shell中可以使用 diff input.txt output.txt)
    # 在Python中也可以读取两个文件内容进行比较
    with open(input_fn, 'r', encoding='utf-8') as f_in_orig, 
         open(output_fn, 'r', encoding='utf-8') as f_out_new:
        if f_in_orig.read() == f_out_new.read():
            print("输入文件与输出文件内容完全一致。")
        else:
            print("警告:输入文件与输出文件内容不一致。")

except ValueError as e:
    exit_err(f"解码错误: {e}")
except FileNotFoundError:
    exit_err(f"文件 '{input_fn}' 未找到。")
except Exception as e:
    exit_err(f"发生意外错误: {e}")

运行上述代码后,通过 diff test.exp check.exp 命令(在Linux/macOS)或比较文件内容,可以验证 check.exp 与 test.exp 完全一致。这种方法提供了对文件格式的最高控制度,是实现精确回溯的首选。

解决方案三:结合正则表达式预处理与Pandas的escapechar

如果需要在读取数据后利用Pandas的强大DataFrame功能进行数据分析和处理,但又必须实现精确的回溯,那么可以采用一种折衷方案:在将数据传递给Pandas之前,使用正则表达式预处理文件内容,将嵌入的引号临时“转义”成Pandas可以理解的形式;在Pandas处理完毕并写入后,再将这些临时转义“还原”。

此方法适用于需要在Pandas DataFrame中进行操作,并且能够接受预处理和后处理的开销。

import csv
import re
from io import StringIO
import pandas as pd

# 示例文件路径
input_fn = "test.exp"
output_fn = "check.exp"

try:
    with open(input_fn, 'r', encoding='utf-8') as f:
        text = f.read()

    # 预处理:使用正则表达式将字段内部的未转义双引号替换为转义形式 "
    # 这里我们假设嵌入的引号通常出现在数字后面,如 5.00"
    # 更通用的模式可能需要根据实际数据调整
    # 原始: "Series ..., 5.00", chem film..."
    # 目标: "Series ..., 5.00"", chem film..." (Pandas能理解)
    # 确保只替换内部的引号,而不是字段的包裹引号
    # 这个正则表达式 (r'(d+.d+)"') 是针对示例数据中 "5.00"" 的情况
    # 对于更复杂的内部引号,可能需要更精细的正则或更复杂的解析逻辑
    text = re.sub(r'(d+.d+)"', r'g<1>\"', text)

    # 使用StringIO将处理后的文本作为文件对象传递给Pandas
    # quotechar='"': 指定双引号为引用字符
    # sep="	": 指定制表符为分隔符
    # escapechar="\": 指定反斜杠为转义字符,这样Pandas会把 " 视为一个字面量引号
    df = pd.read_csv(StringIO(text), quotechar='"', sep="	", escapechar="\", dtype=str)

    # 创建一个StringIO对象用于捕获to_csv的输出
    out_f = StringIO()

    # 将DataFrame写回TSV格式
    df.to_csv(
        out_f,
        sep="	",
        quoting=csv.QUOTE_ALL,  # 强制所有字段都被引用
        doublequote=False,      # 禁用双重引用内部引号(因为我们使用了escapechar)
        escapechar="\",        # 使用反斜杠转义内部引号
        index=False,            # 不写入DataFrame索引
    )

    # 获取to_csv的输出文本
    text_output = out_f.getvalue()

    # 后处理:将Pandas生成的转义引号 " 还原为原始的未转义引号 "
    text_output = text_output.replace(r""", '"')

    # 将最终文本写入输出文件
    with open(output_fn, "w", encoding='utf-8') as f_out:
        f_out.write(text_output)

    print(f"文件 '{input_fn}' 已通过Pandas处理并以相同格式写回至 '{output_fn}'。")
    # 验证输入与输出是否完全一致
    with open(input_fn, 'r', encoding='utf-8') as f_in_orig, 
         open(output_fn, 'r', encoding='utf-8') as f_out_new:
        if f_in_orig.read() == f_out_new.read():
            print("输入文件与输出文件内容完全一致。")
        else:
            print("警告:输入文件与输出文件内容不一致。")

except FileNotFoundError:
    print(f"错误:文件 '{input_fn}' 未找到。", file=sys.stderr)
    sys.exit(1)
except Exception as e:
    print(f"发生意外错误: {e}", file=sys.stderr)
    sys.exit(1)

此方法通过在Pandas读取和写入前后进行字符串级别的转换,成功地利用了Pandas的DataFrame功能,同时实现了原始文件格式的精确回溯。其关键在于 re.sub 的预处理和 replace 的后处理,以及 pd.read_csv 和 df.to_csv 中 escapechar 参数的正确使用。

总结与注意事项

处理带有嵌入未转义双引号的制表符分隔文件是一项挑战,尤其是在需要实现精确回溯时。本文介绍了三种主要策略:

  1. csv 模块与手动剥离: 适用于仅需读取数据并剥离外层引号进行内部处理的场景。对于写回原始“坏”格式,需要额外的定制化编码。
  2. 自定义解码与编码函数: 这是实现输入与输出文件字节级精确匹配的最直接和最可靠的方法。它提供了对文件格式的完全控制,适用于对数据完整性要求极高的场景。
  3. Pandas结合正则表达式预处理与escapechar: 当需要在读取数据后利用Pandas DataFrame进行复杂的数据操作时,此方法提供了一个优雅的解决方案。它通过临时转义和还原嵌入的引号,使得Pandas能够正确处理数据,同时满足回溯要求。

注意事项:

  • 理解数据格式: 在选择任何方法之前,务必彻底理解文件的具体“坏”格式。嵌入引号的模式、是否存在其他特殊字符(如未转义的制表符或换行符)都会影响方法的选择和实现细节。
  • 性能考量: 对于非常大的文件,自定义逐行处理(方法二)或正则表达式预处理(方法三)可能会比Pandas默认的C引擎解析稍慢。但对于非标准格式,性能往往需要让步于数据准确性。
  • 可维护性: 自定义解码/编码函数虽然强大,但需要仔细维护,以确保它能适应未来可能出现的格式变动。
  • 最佳实践: 尽可能推动数据源提供符合标准CSV/TSV规范的文件。这可以大大简化数据处理的复杂性。

通过选择适合您具体需求的方法,您可以有效地处理这些非标准数据文件,确保数据在整个处理流程中的完整性和一致性。

热门AI工具

更多
DeepSeek

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

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

WorkBuddy

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

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

豆包大模型

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

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

3676

2023.06.20

正则表达式不包含
正则表达式不包含

正则表达式,又称规则表达式,,是一种文本模式,包括普通字符和特殊字符,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式的文本。php中文网给大家带来了有关正则表达式的相关教程以及文章,希望对大家能有所帮助。

2161

2023.07.05

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

5802

2023.07.05

java正则表达式匹配字符串
java正则表达式匹配字符串

在Java中,我们可以使用正则表达式来匹配字符串。本专题为大家带来java正则表达式匹配字符串的相关内容,帮助大家解决问题。

772

2023.08.11

正则表达式空格
正则表达式空格

正则表达式空格可以用“s”来表示,它是一个特殊的元字符,用于匹配任意空白字符,包括空格、制表符、换行符等。本专题为大家提供正则表达式相关的文章、下载、课程内容,供大家免费下载体验。

500

2023.08.31

Python爬虫获取数据的方法
Python爬虫获取数据的方法

Python爬虫可以通过请求库发送HTTP请求、解析库解析HTML、正则表达式提取数据,或使用数据抓取框架来获取数据。更多关于Python爬虫相关知识。详情阅读本专题下面的文章。php中文网欢迎大家前来学习。

653

2023.11.13

正则表达式空格如何表示
正则表达式空格如何表示

正则表达式空格可以用“s”来表示,它是一个特殊的元字符,用于匹配任意空白字符,包括空格、制表符、换行符等。想了解更多正则表达式空格怎么表示的内容,可以访问下面的文章。

366

2023.11.17

正则表达式中如何匹配数字
正则表达式中如何匹配数字

正则表达式中可以通过匹配单个数字、匹配多个数字、匹配固定长度的数字、匹配整数和小数、匹配负数和匹配科学计数法表示的数字的方法匹配数字。更多关于正则表达式的相关知识详情请看本专题下面的文章。php中文网欢迎大家前来学习。

679

2023.12.06

AI视频生成软件推荐
AI视频生成软件推荐

本专题汇总了当前主流的AI视频生成软件推荐与排行榜单,涵盖seko、AniShort、剧云、Lovart、LiblibAI及立刻mv等热门工具。同时整理了各软件在文生视频、图生视频、时长限制、画质表现及免费额度等方面的差异对比,助您快速选对适合创作需求的AI视频生成工具。

120

2026.09.16

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Valgrind支持平台说明
Valgrind支持平台说明

共0课时 | 0人学习

CLion 远程开发实战
CLion 远程开发实战

共0课时 | 0人学习

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

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