Perl中替换与split处理CRLF换行符的问题排查与修复
Perl处理带CRLF换行符的CSV转换问题
问题背景
需要处理一批带有CRLF换行符的文本文件,完成以下转换:
- 移除每行最后一个
$符号 - 将所有
$替换为逗号, - 为每个字段添加双引号
- 重命名输出为CSV文件
原始文件示例
$ cat -v file1.txt 1$XXX$ZZZ$$$$$$$$^M 2$AAA$BBB$$$$$$$$^M $ cat -v file2.txt 1$4668$$$^M 2$46$$$^M
期望输出
$ cat newname1.csv "1","XXX","ZZZ","","","","","","","" "2","AAA","BBB","","","","","","","" $ cat newname2.csv "1","4668","","" "2","46","",""
尝试的代码及异常输出
用户最初的Perl代码运行后,CRLF的^M被保留为最后一个字段,导致输出异常:
#!/usr/bin/perl use strict; use warnings; my %inputs = qw( file1 file1.txt file2 file2.txt ); my %outputs = qw( file1 newname1.csv file2 newname2.csv ); for my $key (keys %inputs) { open my $in, '<', $inputs{$key} or die $!; open my $out, '>', $outputs{$key} or die $!; while(<$in>) { local $, = ','; local $\ = "\n"; s/\$$//; my @row = split /\$/; print $out map qq("$_"), @row; } close $in or die $!; close $out or die $!; }
异常输出:
$ cat -v newname1.csv "1","XXX","ZZZ","","","","","","","","","^M " "2","AAA","BBB","","","","","","","","","^M " $ cat -v newname2.csv "1","4668","","","^M " "2","46","","","^M "
用户尝试过的无效方案:
- 改用
<:crlf打开文件,结果无改善 - 使用
\$\r\n/\$\R匹配行尾$,导致丢失末尾空字段
解决方案
问题核心是CRLF的\r(即^M)未被正确清除,且split默认丢弃末尾空字段。修改后的代码如下:
#!/usr/bin/perl use strict; use warnings; my %inputs = qw( file1 file1.txt file2 file2.txt ); my %outputs = qw( file1 newname1.csv file2 newname2.csv ); for my $key (keys %inputs) { # 用:crlf层自动将CRLF转换为LF,统一换行符 open my $in, '<:crlf', $inputs{$key} or die $!; open my $out, '>', $outputs{$key} or die $!; while(<$in>) { chomp; # 移除行尾所有换行符(\r\n或\n),避免^M残留 next if /^\s*$/; # 跳过空行,按需调整 s/\$$//; # 移除行尾最后一个$ # split第三个参数-1:强制保留所有末尾空字段 my @row = split /\$/, $_, -1; # 拼接成标准CSV行 my $csv_line = join ',', map { qq("$_") } @row; print $out "$csv_line\n"; } close $in or die $!; close $out or die $!; }
关键修改说明
<:crlf打开文件:让Perl自动处理CRLF换行符,将其转换为LF,避免手动处理\r的麻烦chomp清除换行符:彻底移除行尾的\r和\n,确保后续正则只处理业务内容split /\$/, $_, -1:默认split会丢弃末尾的空字段,加上-1参数后会保留所有空字段,保证输出的空列数量正确- 手动拼接CSV行:替代
local $,的方式,逻辑更直观,减少隐式行为导致的问题
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

