如何用Perl合并带换行的行扩展内容并解决替换循环错误?
合并带+标记的续行内容
问题场景
输入文件包含主行和以+ 开头的续行,需要将主行和后续对应所有续行合并为单行:
输入示例:
X123 + a b c + d e f g Y4567 + a1 b2 + c1 d2 + e1 f2
期望输出:
X123 a b c d e f g Y4567 a1 b2 c1 d2 e1 f2
原命令报错原因
你使用的perl -00pe 's/\n\+ / /g'出现Substitution loop错误,是因为-00启用了段落模式,会将整个文件(或空行分隔的块)一次性读入内存。全局替换/g会反复扫描字符串,当perl内部检测到匹配逻辑可能陷入循环时,就会触发这个错误。
可行解决方案
方案1:使用awk(推荐,逻辑直观)
awk逐行处理,根据行类型拼接内容:
awk '/^\+/ {printf " %s", substr($0, 3); next} {if (NR>1) print ""; printf "%s", $0} END {print ""}' input.txt
- 逻辑说明:
- 匹配以
+开头的行:截取第3个字符后的内容(去掉+前缀),用printf追加到当前行末尾(前缀加空格) - 匹配主行:如果不是第一行,先打印换行(分隔上一个合并完成的行),再输出主行内容
END块打印最后一行的换行,保证文件格式完整
- 匹配以
方案2:修正Perl命令(逐行处理)
放弃段落模式,改用逐行拼接的方式:
perl -ne 'if (/^\+ /) {s/^\+ / /; $line .= $_} else {print "$line\n" if $line; $line = $_} END {print "$line\n"}' input.txt
- 逻辑说明:
- 遇到
+开头的行:去掉前缀后拼接到$line变量 - 遇到主行:如果已有拼接内容,先打印之前的合并行,再重置
$line为当前主行 END块打印最后一条合并后的行
- 遇到
方案3:简化Perl写法(整文件处理)
通过正则精准匹配需要替换的换行:
perl -0 -pe 's/\n\+ / /g; s/\n(?!\+)/\n/g' input.txt
- 逻辑说明:
-0读取整个文件到内存- 第一步把所有
\n+替换为空格,合并续行 - 第二步保留所有不跟
+的换行,作为合并后行的分隔符
内容的提问来源于stack exchange,提问作者Gert Gottschalk
相关产品推荐
相关产品推荐

