Perl脚本合并CSV特定模式间多行异常,求修正方案
问题分析与脚本修正
原脚本的核心问题
- 范围操作符误用:
/Module Statements/ .. /6.4*/会把每一行CSV(每行均以Module Statements开头、6.*结尾)判定为独立范围,完全无法识别引号内的跨多行字段内容。 - 中间行重复输出:在范围中间的行执行
push @collect, $_后循环打印数组,导致内容重复输出。 - 未处理CSV引号内换行:CSV规范中引号内的换行属于同一字段,原脚本未识别此规则,直接拆分每行处理,破坏了字段完整性。
修正后的Perl脚本
#!/usr/bin/perl use strict; use warnings; use feature 'say'; my $in_quote = 0; my @current_line; my $file = $ARGV[0] or die "请输入文件名\n"; open(my $DATA, '<', $file) or die "无法打开文件: $!"; while (<$DATA>) { chomp; # 跟踪引号状态,判断是否处于多行字段内 my $quote_count = s/"/"/g; $in_quote = !$in_quote if $quote_count % 2 != 0; push @current_line, $_; # 不在引号内时,说明当前是完整的CSV行 unless ($in_quote) { my $full_line = join "\n", @current_line; @current_line = (); # 处理引号内的多行内容,按预期格式合并 $full_line =~ s/"([^"]+)"/process_quoted($1)/ge; say $full_line; } } # 处理引号内的文本格式 sub process_quoted { my ($content) = @_; # 替换换行为空格,合并连续空白 $content =~ s/\n+/ /g; $content =~ s/\s+/ /g; # 按预期在每3个?后添加换行,还原排版 my @parts = split /(\?)/, $content; my $processed = ''; my $count = 0; for my $part (@parts) { if ($part eq '?') { $count++; $processed .= $part . ' '; $processed .= "\n" if $count % 3 == 0; } else { $processed .= $part; } } # 清理末尾多余空白,保留开头的换行(如6.4.5.f的格式) $processed =~ s/\s+$//; $processed =~ s/^ /\n/ if $content =~ /^\n/; return "\"$processed\""; }
修正逻辑说明
- 引号状态跟踪:通过统计每行的引号数量,判断是否处于CSV的多行字段(引号内),确保完整读取整个字段内容。
- 字段内容格式化:将引号内的换行替换为空格,再按每3个
?添加换行,匹配预期的排版要求。 - 完整行输出:仅当读取完完整的CSV行(退出引号状态)时,才处理并输出内容,保证CSV结构的正确性。
内容的提问来源于stack exchange,提问作者kshitij kulshreshtha
相关产品推荐
相关产品推荐

