如何按条件筛选固定宽度文本文件行并保留原格式?
固定宽度文本文件筛选解决方案
问题描述
原始固定宽度格式文本文件内容:
a1 b c1 d -> header 1 2 3 4 6 4 3 5 a2 b c2 d2 -> header 7 9 1 4 a b1 c6 d2 -> header 8 9 3 4
筛选规则:
- 若某行c列值为3且b列值不为2,保留该行及其对应的表头
- 若c列值不为3,不保留该行及其表头
期望输出:
a1 b c1 d 6 4 3 5 a b1 c6 d2 8 9 3 4
注:值3仅出现在c列,值2仅出现在b列,无需校验列位置,只需满足筛选条件即可保留对应表头。用户尝试过pandas的read_fwf()读取,但输出格式无法保持原始固定宽度,因此寻求纯Python、Bash或PowerShell解决方案。
纯Python实现
思路:逐行读取文件,记录当前表头,检查数据行是否符合条件,符合则写入表头(仅第一次遇到符合条件的数据行时写入)和数据行,完全保留原始固定宽度格式。
def filter_fixed_width_file(input_path, output_path): current_header = None header_written = False # 标记当前表头是否已写入输出文件 with open(input_path, 'r') as infile, open(output_path, 'w') as outfile: for line in infile: stripped_line = line.strip() # 判断是否是表头行(包含"-> header"标记) if '-> header' in stripped_line: # 提取表头内容,去掉标记部分 current_header = line.split('-> header')[0].rstrip() + '\n' header_written = False # 新表头出现,重置标记 continue # 处理数据行 # 按空格分割(固定宽度分割,split()自动处理多空格) parts = stripped_line.split() # 检查是否符合条件:c列值为3且b列值不为2 if len(parts) >=3 and parts[2] == '3' and parts[1] != '2': if not header_written: outfile.write(current_header) header_written = True outfile.write(line) # 使用示例 filter_fixed_width_file('input.txt', 'output.txt')
Bash脚本实现
思路:用awk工具跟踪当前表头,匹配符合条件的数据行时输出表头(仅一次)和数据行,利用awk默认的空格分割特性处理固定宽度列。
awk ' /-> header/ { # 提取表头,去掉"-> header"部分及后续内容 sub(/ *-> header.*/, "", $0) current_header = $0 header_printed = 0 next } { # 检查条件:第三列是3,第二列不是2 if ($3 == "3" && $2 != "2") { if (!header_printed) { print current_header header_printed = 1 } print $0 } } ' input.txt > output.txt
PowerShell脚本实现
思路:遍历文件行,识别并存储表头,检查数据行的列值条件,符合则输出表头(未输出过的话)和当前行,保持原始行的格式。
$inputPath = "input.txt" $outputPath = "output.txt" $currentHeader = $null $headerWritten = $false # 清空输出文件 if (Test-Path $outputPath) { Remove-Item $outputPath } Get-Content $inputPath | ForEach-Object { $line = $_ if ($line -match '-> header') { # 提取表头内容,移除标记部分 $currentHeader = $line -replace '\s*-> header.*', '' $headerWritten = $false return } # 分割数据行(处理多空格) $parts = $line.Trim() -split '\s+' if ($parts.Count -ge 3 -and $parts[2] -eq '3' -and $parts[1] -ne '2') { if (-not $headerWritten) { Add-Content -Path $outputPath -Value $currentHeader -Encoding utf8 $headerWritten = $true } Add-Content -Path $outputPath -Value $line -Encoding utf8 } }
内容的提问来源于stack exchange,提问作者franco mango
相关产品推荐
相关产品推荐

