C#转换空格分隔TXT为CSV时如何保留空记录实现合规输出
固定列宽文本转CSV的正确实现方案
方案失效的核心原因
此前使用正则将连续空格替换为逗号的方案存在本质逻辑偏差:
该逻辑默认源文件是任意空白分隔的变长结构,但你的源文件是固定列宽结构——每一列的内容严格占据行内的固定字符位置,列之间的连续空格既可能是两个相邻值的间隔,也可能是某几列本身为空值。直接把连续空格替换为单个逗号的逻辑,会把多列空值对应的连续空格识别成单个分隔符,直接跳过空列,最终导致列数错位。
标准实现流程
固定列宽文件格式转换的核心是按字符物理位置识别列,不依赖空白字符的匹配判断列边界,具体步骤:
- 梳理全量数据的15列固定边界
先抽取20-30行覆盖空值、满值场景的典型内容,逐行标记每列内容的起止字符索引,确保同列的所有值都落在同一个固定区间内。如果手动梳理工作量较大,可逐字符统计全文件的非空值密度,连续高密度区间就是实际存值的列范围,低密度的间隔位置就是列边界,自动生成15列的起止索引表。 - 逐行按边界切片取值
对每一行读取的文本,按照预先定义的列边界区间做字符串截取;截取时处理边界情况:如果当前行长度短于列的截止位置,就以行的实际长度作为截取终点,避免数组越界。每个截取结果仅去掉首尾多余的填充空格,不修改内容本身的内部字符。 - 拼接生成CSV行
将所有截取得到的列值,用逗号做分隔符直接拼接,空值会自动以连续两个逗号的形式保留在对应位置,完全匹配要求的15列对齐规则。
可直接适配的C#参考代码
// 列边界定义:每个条目为(列起始索引, 列截止索引),需根据实际文件调整数值 var columnBounds = new List<(int Start, int End)> { (0, 21), // 第1列:POL编号列 (22, 31), // 第2列:第一数值列 (32, 41), // 第3列:第二数值列 // 按实际15列的边界补全剩余条目 (95, 150) // 最后一列设置足够大的截止值,覆盖所有行的行尾内容 }; var sourceFilePath = @"D:\source.txt"; using (StreamWriter sw = new StreamWriter(@"D:\output.csv")) { using (var fs = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read)) { using (var sr = new StreamReader(fs, Encoding.UTF8)) { string line; while ((line = sr.ReadLine()) != null) { var rowValues = new List<string>(); foreach (var bound in columnBounds) { // 处理行长短于列截止位置的越界问题 int actualEnd = Math.Min(bound.End, line.Length); // 截取对应位置的列内容,仅去掉首尾填充空格 string columnValue = line.Substring(bound.Start, actualEnd - bound.Start).Trim(); rowValues.Add(columnValue); } // 直接拼接生成CSV行,空值自动保留为连续逗号 sw.WriteLine(string.Join(",", rowValues)); } } } }
输出效果说明
- 逻辑层面完全按固定位置识别列,不会因为连续空格的数量变化出现列偏移:如果某行的第14、15列无填充值,对应位置的截取结果为空字符串,拼接后会形成连续两个逗号,和示例要求的输出格式完全一致。
- 不需要额外判断空值逻辑,只要列边界定义准确,空记录会自动完整保留,不会出现丢列、列错位的问题。
注意:固定列宽格式的转换不存在“不指定边界、纯靠正则自动识别所有空值”的通用方案,列边界的确认是转换准确的必要前置步骤。
内容的提问来源于stack exchange,提问作者JustToKnow
相关产品推荐
相关产品推荐

