Pandas中处理内嵌双引号的制表符分隔文件:读写策略与最佳实践

花韻仙語
发布: 2025-11-14 13:25:01
原创
644人浏览过

pandas中处理内嵌双引号的制表符分隔文件:读写策略与最佳实践

处理Pandas中带有内嵌双引号的制表符分隔文件时,标准解析常因字段内外双引号的冲突而导致数据损坏。本教程深入探讨了三种解决方案:一是利用Python `csv` 模块忽略引用并手动解析;二是自定义解码与编码函数,实现对特定“坏格式”的完美往返读写;三是结合正则表达式预处理和Pandas的`escapechar`参数。这些方法旨在确保数据完整性,并准确还原原始文件格式,帮助开发者有效应对复杂数据导入导出场景。

在数据处理过程中,我们经常会遇到需要导入和导出制表符分隔文件(TSV)的场景。然而,当这些文件中存在特殊情况,例如字段内容本身包含双引号,并且整个字段又被双引号包裹时,标准的解析库如Pandas的read_csv或Python内置的csv模块可能会因为默认的引用处理机制而导致数据被“破坏”。本教程将详细介绍如何有效应对这种挑战,确保数据在读写过程中保持其原始完整性。

考虑以下一个典型的制表符分隔文件 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")。如果直接使用 pd.read_csv 并尝试写回,可能会得到如下结果:

原始字段: "Series 48SL–5 WEDGE–LOK, 2-56UNC-2B, 5.00", chem film, lock washer and flat"

写回后可能变为: "Series 48SL–5 WEDGE–LOK, 2-56UNC-2B, 5.00, chem film, lock washer and flat"""

这表明Pandas在读取时可能将内部的引号错误地解释为字段的结束,或者在写入时为了符合CSV标准而对内部引号进行了不必要的转义(例如,双引号变为两个双引号)。我们的目标是实现输入与输出的精确匹配。

方法一:使用 csv 模块进行手动解析

这种方法适用于文件格式严格遵循以下规则的场景:

  1. 所有字段都以双引号开始和结束(即外部引用)。
  2. 字段内容本身不包含制表符或换行符。

其核心思想是,在读取时指示 csv 模块忽略引用处理,然后手动通过字符串切片去除字段的外部双引号。

解析数据

import csv

def parse_tsv_with_manual_quoting(filepath: str) -> list[list[str]]:
    """
    解析一个制表符分隔文件,该文件的字段被双引号包裹,且内部可能含有双引号。
    通过忽略引用并手动切片来处理。
    """
    rows: list[list[str]] = []
    with open(filepath, newline="", encoding='utf-8') as f:
        # 使用 csv.QUOTE_NONE 忽略引用,并指定制表符为分隔符
        reader = csv.reader(f, delimiter="	", quoting=csv.QUOTE_NONE)

        # 处理标题行:去除外部双引号
        header = [x[1:-1] for x in next(reader)]
        rows.append(header) # 将处理后的标题也加入rows,或单独保存

        # 处理数据行:去除每个字段的外部双引号
        for row in reader:
            processed_row = [x[1:-1] for x in row]
            rows.append(processed_row)
    return rows[0], rows[1:] # 返回标题和数据

# 示例使用
exp_fn = "test.exp"
header, data_rows = parse_tsv_with_manual_quoting(exp_fn)
print("Header:", header)
print("Data Rows:")
for row in data_rows:
    print(row)
登录后复制

上述代码将正确解析出以下数据结构:

Header: ['HEADER', 'ID', 'Part Reference', 'Value', 'Part_Description']
Data Rows:
['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']
登录后复制

写回数据(保持原始格式)

如果目标是将数据写回 原始的“坏格式”,即每个字段都被双引号包裹,且内部的双引号不进行额外转义,则需要手动添加外部双引号。

def write_tsv_with_manual_quoting(filepath: str, header: list[str], data_rows: list[list[str]]):
    """
    将解析后的数据写回制表符分隔文件,并保持原始的“坏格式”。
    """
    with open(filepath, "w", newline="", encoding='utf-8') as f:
        writer = csv.writer(f, delimiter="	", quoting=csv.QUOTE_NONE)
        # 手动为每个字段添加外部双引号
        writer.writerow([f'"{field}"' for field in header])
        for row in data_rows:
            writer.writerow([f'"{field}"' for field in row])

# 示例使用
output_fn = "check_manual.exp"
write_tsv_with_manual_quoting(output_fn, header, data_rows)
print(f"数据已写回至 {output_fn},请检查其格式是否与原始文件一致。")
登录后复制

注意事项:

白果AI论文
白果AI论文

论文AI生成学术工具,真实文献,免费不限次生成论文大纲 10 秒生成逻辑框架,10 分钟产出初稿,智能适配 80+学科。支持嵌入图表公式与合规文献引用

白果AI论文 61
查看详情 白果AI论文
  • 这种方法对输入文件的格式假设非常严格。如果字段不是都由双引号包裹,或者内部含有制表符/换行符,则此方法可能失效。
  • quoting=csv.QUOTE_NONE 意味着 csv 模块不会处理任何引用,所有双引号都将被视为普通字符。

方法二:自定义解码与编码函数实现完美往返

当需要确保输入文件和输出文件在字节级别上完全一致时,自定义解码(decode)和编码(encode)函数是更精确和鲁棒的选择。这种方法明确地定义了“坏格式”的解析和生成规则。

定义解码与编码逻辑

import sys

END = "
"
"""预期行结束符"""
DELIM = "	"
"""预期分隔符"""
QUOT = '"'
"""预期引用字符"""

Row = list[str]

def decode(line: str) -> Row:
    """
    解码一个“坏格式”的CSV/TSV行。
    确保行以END结尾,按DELIM分割行,并验证每个字段是否以QUOT开始和结束,然后去除这些外部QUOT。
    返回字段列表。
    """
    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:
    """
    将行编码回其原始的“坏格式”。
    """
    # 为每个字段添加外部双引号,然后用制表符连接
    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_filepath = "test.exp"
output_filepath = "check_custom.exp"

decoded_rows: list[Row] = []
with open(input_filepath, encoding='utf-8') as f:
    try:
        header = decode(next(f))
        decoded_rows.append(header)
    except ValueError as e:
        exit_err(f"无法解码标题行: {e}")

    for i, line in enumerate(f):
        try:
            decoded_rows.append(decode(line))
        except ValueError as e:
            exit_err(f"无法解码第 {i+2} 行: {e}") # i从0开始,所以是i+2行

# 编码并写回文件
with open(output_filepath, "w", encoding='utf-8') as f:
    for row in decoded_rows:
        f.write(encode(row))

print(f"数据已通过自定义编解码器处理并写回至 {output_filepath}。")

# 验证输入输出一致性
# 在命令行中运行:python your_script_name.py; diff test.exp check_custom.exp
# 如果没有任何输出,则表示文件内容完全一致。
登录后复制

这种方法的优点是其精确性和鲁棒性。通过明确定义解码和编码规则,我们可以确保即使面对非标准的“坏格式”文件,也能实现数据的完美往返,从而保证输入和输出文件在内容和格式上完全一致。

方法三:结合正则表达式预处理和Pandas参数

这种方法尝试在Pandas的框架内解决问题,通过在读取前对文件内容进行正则表达式预处理,并在写入时配置 to_csv 参数,以期达到与原始格式匹配的效果。

预处理与Pandas读写

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

input_filepath = "test.exp"
output_filepath = "check_pandas_re.exp"

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

# 预处理:将形如 '数字.数字"' 的内部双引号转义为 '数字.数字"'
# 这样Pandas在读取时,可以通过 escapechar='\' 识别并正确处理
text = re.sub(r'(d+.d+)"', r'g<1>\"', text)

# 使用 StringIO 将预处理后的文本作为文件对象传递给 Pandas
df = pd.read_csv(StringIO(text), quotechar='"', sep="	", escapechar="\")

# 准备输出文件
out_f = StringIO()

# 写入CSV:
# sep="	":制表符分隔
# quoting=csv.QUOTE_ALL:所有字段都用双引号包裹
# doublequote=False:不将内部双引号转义为双倍双引号
# escapechar="\":使用反斜杠作为转义字符,对应我们之前的预处理
# index=False:不写入DataFrame的索引
df.to_csv(
    out_f,
    sep="	",
    quoting=csv.QUOTE_ALL,
    doublequote=False,
    escapechar="\",
    index=False,
)

# 获取Pandas写入后的字符串
output_text = out_f.getvalue()

# 后处理:将转义的反斜杠还原,以匹配原始的“坏格式”
output_text = output_text.replace(r'"', '"')

with open(output_filepath, "w", encoding='utf-8') as f:
    f.write(output_text)

print(f"数据已通过Pandas结合正则表达式处理并写回至 {output_filepath}。")
# 同样可以通过 diff 命令验证 input_filepath 和 output_filepath 的一致性
登录后复制

注意事项:

  • 正则表达式 r'(d+.d+)"' 仅针对特定模式(数字.数字后跟双引号)的内部引号进行转义。如果内部引号的模式更复杂,需要调整正则表达式。
  • doublequote=False 是关键,它指示 csv.writer 不将内部的 " 转义为 ""。
  • escapechar="\" 则告诉 csv.writer 使用反斜杠来转义内部的 "。
  • 这种方法需要对输入文件的内部引号模式有清晰的了解,并编写相应的正则表达式。过度或错误的预处理可能导致新的问题。

总结与选择建议

处理带有内嵌双引号的制表符分隔文件,尤其当需要保持原始的“坏格式”时,选择合适的策略至关重要。

  • 如果您的主要目标是读取数据并将其导入到应用程序中进行处理,并且文件格式严格(所有字段被外部双引号包裹,内部无制表符/换行符),那么 方法一(使用 csv 模块手动解析) 是最简洁高效的。它直接获取了干净的数据。

  • 如果您的核心需求是实现输入文件和输出文件在格式和内容上的完美往返(即,即使原始格式“不标准”,也要精确还原),那么 方法二(自定义解码与编码函数) 是最可靠和精确的。它提供了对解析和生成过程的完全控制,适用于对数据保真度要求极高的场景。

  • 如果您希望尽量利用Pandas的强大功能,并且能够接受通过正则表达式对文件内容进行预处理和后处理,那么 方法三(结合正则表达式预处理和Pandas参数) 是一种选择。但请注意,这需要对正则表达式有良好的掌握,并且可能需要根据实际文件中的内部引号模式进行细致调整。

在实际应用中,理解数据源的具体“坏格式”是解决问题的关键。根据格式的复杂性和对数据往返保真度的要求,选择最适合的方法。通常,对于非标准格式,自定义的解析逻辑(方法二)能提供最大的灵活性和准确性。

以上就是Pandas中处理内嵌双引号的制表符分隔文件:读写策略与最佳实践的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
热门推荐
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

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