Perl使用钻石操作符读取文件到数组时避免额外换行的方法
问题与解决方案
原始问题
尝试用Perl的钻石操作符通过my @array = <$filehandle>;将文本文件读入数组,误以为无论原文件最后一行是否有换行符,该操作都会为其添加\n。尝试过用undef $/将文件读入标量再拆分,但拆分结果和预期不符,且开销较大,同时不能用chomp,因为需要保留原文件最后一行的换行状态。
测试代码与异常输出
测试文件test2内容为first line\nsecond line时,执行以下代码:
my $file = 'test2'; my @lines = &slurp($file); for (@lines) { print "-$_-\n"; } sub slurp { my $f = shift; open(my $fh, '<', $f) or die $!; my @ary = <$fh>; return @ary; }
输出:
-first line - -second line -
当test2内容改为first line\nsecond line\n时,输出:
-first line - -second line - - -
问题根源
Perl的<$filehandle>读取行为是准确的:不会为无换行的最后一行添加换行符。测试结果异常是因为vim默认会在文件末尾自动添加换行符,导致你以为的"无换行最后一行"实际上已经被编辑器修改过。
可以用cat -A test2命令查看文件实际内容,其中$符号代表换行符,以此确认文件末尾的真实状态。
正确处理方式
- 编辑器设置调整:如果需要创建末尾无换行的文件,在vim中可以先执行
set noeol,编辑完成后保存;之后可以用set eol恢复默认设置。 - Perl读取的正确用法:直接使用
<$filehandle>读取即可准确保留每行的原始换行状态,无需额外处理。 - 拆分标量的正确姿势:如果确实需要通过读取整个文件再拆分的方式,需给
split添加第三个参数-1来保留末尾空元素,示例:
open my $fh, '<', $file or die $!; undef $/; my $content = <$fh>; my @lines = split /\n/, $content, -1;
这样拆分"hello\nworld\n"会得到("hello", "world", ""),但这种方法开销高于直接读取行,仅适合特殊场景。
内容的提问来源于stack exchange,提问作者Maelstrom
相关产品推荐
相关产品推荐

