如何用Perl匹配连续双换行符并提取结果表格末尾数据
Perl解析日志文件表格最后一行数值的问题解决
问题分析
你的代码存在几个关键问题导致正则匹配失败:
- 换行符被移除:你用
chomp读取每行数据,这会把每行末尾的换行符(包括\r\n)去掉,正则里的\r\n\r\n根本无法匹配到任何内容。 - 逐行处理无法跨行匹配:原思路是通过表格后的连续两个换行定位,但逐行遍历的方式无法捕捉跨行的模式。
- 语法错误:多处
if语句缺失大括号、OUT文件句柄未打开、文件关闭位置错误等,这些都会导致代码运行异常。
修正后的代码
#!/usr/bin/perl -w use strict; use Getopt::Long; my ($path); GetOptions( 'path=s' => \$path, ); chdir $path or die "ERROR: Unable to enter $path: $!\n"; # 打开输出文件 open(my $out_fh, '>', 'assembly_results.tsv') or die "ERROR: Unable to create output file: $!\n"; # 打印表头 print $out_fh "sample\tAssembly\tMapping\n"; opendir(my $temp_dir, ".") or die "ERROR: Unable to open directory: $!\n"; my @files = readdir($temp_dir); closedir($temp_dir); for my $file (@files) { next unless $file =~ /(\w+)_LRassembly.unicycler.log/; my $sample = $1; my ($mAssize, $qualAssize); open(my $in_fh, '<', $file) or die "ERROR: Unable to open $file: $!\n"; # 读取整个文件为单个字符串,保留换行符 local $/; my $content = <$in_fh>; close($in_fh); # 匹配表格最后一行的数值,后面跟着连续两个换行(兼容不同换行格式) if ($content =~ /(\d{1,3}(?:,\d{3})+)\s+(\d{1,3}(?:,\d{3})+\.\d+)\s*\n\s*\n/) { $mAssize = $1; $qualAssize = $2; print "Matched $sample: $mAssize | $qualAssize\n"; } else { warn "WARNING: No matching data found in $file\n"; $mAssize = 'N/A'; $qualAssize = 'N/A'; } print $out_fh "$sample\t$mAssize\t$qualAssize\n"; } close($out_fh);
修改说明
- 读取整个文件内容:使用
local $/取消输入记录分隔符,把整个文件读成一个字符串,这样就能匹配跨行的连续换行模式。 - 优化正则表达式:
- 用
\d{1,3}(?:,\d{3})+更精准匹配带逗号分隔的整数(比如1,712,611) - 用
\s*\n\s*\n匹配连续两个换行,兼容可能存在的空白字符
- 用
- 修复语法问题:
- 补全所有
if语句的大括号 - 使用词法文件句柄(
$in_fh、$out_fh)替代旧式裸句柄,更安全 - 提前打开输出文件并打印表头,确保输出格式正确
- 处理未匹配到数据的情况,避免输出空值
- 补全所有
验证结果
运行修正后的代码,会生成assembly_results.tsv文件,内容格式符合你的预期:
| sample | Assembly | Mapping |
|---|---|---|
| NKC1231 | 1,685,628 | 33,682.91 |
内容的提问来源于stack exchange,提问作者JLLavin
相关产品推荐
相关产品推荐

