
本教程详细介绍了如何使用python处理格式不规范、以空格作为分隔符的文本文件,并将其转换为标准的csv格式。由于此类文件分隔符不一致且可能存在字段内部空格,标准库方法往往失效。文章通过自定义正则表达式解析函数,区分字段分隔符与内容空格,逐步实现文件读取、头部解析、数据行处理及最终csv输出,并强调了解决方案的数据依赖性及优化考量。
在数据处理过程中,我们经常会遇到格式不规范的文本文件。这些文件可能使用不一致的空格数量作为字段分隔符,甚至在字段内容内部也包含空格,这使得传统的 pandas.read_csv 等方法难以准确解析。例如,当尝试使用 sep='\t' 或 sep=r"\s{2,}" 时,可能无法正确识别列边界,导致数据错位。对于这类“坏文件”,需要采用更精细的自定义解析策略。
处理不规范文本文件的核心在于精确识别哪些空格序列是字段分隔符,哪些是字段内容的一部分。本教程将展示如何通过逐行读取文件,并利用正则表达式结合自定义替换函数(re.sub 与 replfunc)来解决这一问题。其基本思想是:
首先,我们需要打开并逐行读取文本文件。为了确保行尾字符不影响后续处理,通常会移除每行的换行符。
import sys
import re
import pandas as pd
def parse_bad_txt_to_csv(input_filepath, output_filepath):
    table = []
    with open(input_filepath, 'r', encoding='utf-8') as f:
        lines = f.readlines()
    for i, line in enumerate(lines):
        line = line.rstrip('\n') # 移除行尾换行符
        # ... 后续解析逻辑 ...通常,文件头(第一行)的字段分隔符可能相对一致,或者其结构可以通过简单的多空格分割来处理。
立即学习“Python免费学习笔记(深入)”;
        if i == 0:
            # 假设标题行中没有内部空格,可以直接按两个或更多空格分割
            header_row = re.split(r' {2,}', line)
            table.append(header_row)
            continue文件头和数据行之间可能存在空白行,这些行可以直接跳过。
        if not line.strip(): # 检查是否为空白行
            continue这是整个解析过程中最复杂也是最核心的部分。我们需要定义一个替换函数 replfunc,它将根据匹配到的空格序列的长度和上下文,决定是将其视为字段分隔符还是字段内容的一部分。
        def replfunc(mo):
            L = len(mo.group(0)) # 获取匹配到的空格序列长度
            # 特殊情况处理:例如,某些字段内部的两个空格应被保留为一个空格
            # 示例数据中 "Rejected at  level." 内部有两个空格,应视为一个内部空格
            (start, end) = mo.span()
            if L == 2:
                if (
                    line[:start].endswith('Rejected at')
                    and
                    line[end:].startswith('level.')
                ):
                    return ' ' # 替换为单个空格,作为字段内容
            # 其他情况:根据空格长度判断其作为字段分隔符的含义
            # 这些长度是根据具体数据模式观察得出的经验值
            if L < 2:
                # 理论上不应匹配到小于2个空格的序列,除非是特殊情况
                return mo.group(0) # 保留原样或抛出错误
            elif 2 <= L <= 12: # 较短的空格序列可能代表一个字段分隔符
                return '\t'
            elif L == 17: # 特定长度的空格序列可能代表多个空字段
                return '\t\t'
            elif L == 43:
                return '\t\t\t'
            elif L == 61:
                return '\t\t\t\t\t'
            elif L == 120:
                return '\t'
            elif L == 263:
                return '\t'
            else:
                # 如果遇到未预期的空格长度,可以返回原始空格或标记
                print(f"Warning: Unhandled space length {L} at line {i+1}")
                return '\t' # 默认替换为制表符
        # 使用 replfunc 替换所有两个或更多空格的序列
        tabbed_line = re.sub(r'\s{2,}', replfunc, line)
        row = tabbed_line.split('\t')
        table.append(row)解析逻辑详解:
解析完所有行后,table 变量将包含一个列表的列表,每个内部列表代表一行数据。我们可以利用 pandas.DataFrame 将其转换为数据框,然后轻松导出为CSV。
    # 转换为 Pandas DataFrame
    # 确保所有行具有相同的列数,不足的用空字符串填充
    max_cols = max(len(row) for row in table)
    padded_table = [row + [''] * (max_cols - len(row)) for row in table]
    df = pd.DataFrame(padded_table[1:], columns=padded_table[0]) # 第一行为列名
    # 导出为CSV文件
    df.to_csv(output_filepath, index=False, encoding='utf-8')
    print(f"文件 '{input_filepath}' 已成功转换为 '{output_filepath}'。")
# 示例使用
# 假设你的不规范文本文件名为 'input.txt'
# parse_bad_txt_to_csv('input.txt', 'output.csv')import sys
import re
import pandas as pd
def parse_bad_txt_to_csv(input_filepath, output_filepath):
    """
    解析不规范的空格分隔文本文件,并将其转换为CSV文件。
    参数:
        input_filepath (str): 输入文本文件的路径。
        output_filepath (str): 输出CSV文件的路径。
    """
    table = []
    try:
        with open(input_filepath, 'r', encoding='utf-8') as f:
            lines = f.readlines()
    except FileNotFoundError:
        print(f"错误: 文件 '{input_filepath}' 未找到。")
        return
    except Exception as e:
        print(f"读取文件时发生错误: {e}")
        return
    for i, line in enumerate(lines):
        line = line.rstrip('\n') # 移除行尾换行符
        if i == 0:
            # 第一行作为文件头,假设其字段分隔符相对一致
            header_row = re.split(r' {2,}', line)
            table.append(header_row)
            continue
        if not line.strip(): # 检查是否为空白行
            continue
        # 定义替换函数,用于将不同长度的空格序列转换为制表符或单个空格
        def replfunc(mo):
            L = len(mo.group(0)) # 获取匹配到的空格序列长度
            # 特殊情况处理:例如,"Rejected at  level." 中的两个空格应被保留为一个空格
            (start, end) = mo.span()
            if L == 2:
                if (
                    line[:start].endswith('Rejected at')
                    and
                    line[end:].startswith('level.')
                ):
                    return ' ' # 替换为单个空格,作为字段内容
            # 其他情况:根据空格长度判断其作为字段分隔符的含义
            # 这些长度是根据具体数据模式观察得出的经验值,需要根据实际文件调整
            if L < 2:
                # 理论上不应匹配到小于2个空格的序列,除非是特殊情况
                # 这里可以根据需要进行更严格的错误处理或保留原始匹配
                return mo.group(0) 
            elif 2 <= L <= 12:
                return '\t'
            elif L == 17:
                return '\t\t'
            elif L == 43:
                return '\t\t\t'
            elif L == 61:
                return '\t\t\t\t\t'
            elif L == 120:
                return '\t'
            elif L == 263:
                return '\t'
            else:
                print(f"警告: 第 {i+1} 行发现未处理的空格长度 {L}。默认替换为制表符。")
                return '\t' # 默认替换为制表符,可能需要根据实际情况调整
        try:
            tabbed_line = re.sub(r'\s{2,}', replfunc, line)
            row = tabbed_line.split('\t')
            table.append(row)
        except Exception as e:
            print(f"处理第 {i+1} 行时发生错误: {e}。原始行: '{line}'")
            continue
    if not table:
        print("警告: 未解析到任何数据。")
        return
    # 转换为 Pandas DataFrame
    # 确保所有行具有相同的列数,不足的用空字符串填充
    max_cols = max(len(row) for row in table)
    padded_table = [row + [''] * (max_cols - len(row)) for row in table]
    # 第一行为列名,其余为数据
    if len(padded_table) > 1:
        df = pd.DataFrame(padded_table[1:], columns=padded_table[0])
    else: # 只有头部或没有数据行
        df = pd.DataFrame(columns=padded_table[0])
    # 导出为CSV文件
    try:
        df.to_csv(output_filepath, index=False, encoding='utf-8')
        print(f"文件 '{input_filepath}' 已成功转换为 '{output_filepath}'。")
    except Exception as e:
        print(f"导出CSV文件时发生错误: {e}")
# 假设你的不规范文本文件名为 'input.txt',输出文件名为 'output.csv'
# 为了运行此代码,请创建一个名为 'input.txt' 的文件,并将问题中的数据粘贴进去。
# 然后取消注释下面一行并运行。
# parse_bad_txt_to_csv('input.txt', 'output.csv')
数据依赖性与通用性:
鲁棒性与错误处理:
性能考量:
将不规范的文本文件转换为结构化的CSV格式是一项常见但可能具有挑战性的任务。当标准库函数无法满足需求时,自定义Python脚本结合正则表达式提供了一个强大而灵活的解决方案。通过精确识别并替换字段分隔符,我们可以有效地从混乱的文本数据中提取出有用的信息。然而,这种方法的有效性高度依赖于对具体数据模式的理解和细致的规则定义,因此在实际应用中需要仔细分析和调整。
以上就是Python自定义解析不规范文本文件为CSV教程的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号