带捕获组的Perl正则表达式失效,如何保留每组首行?
Perl正则无法实现每组仅保留首行的原因分析
原始文件内容
/Users/x/-acite _1660475490N.html /Users/x/-acite _1660464772N.html /Users/x/-acite _1660464242N.html /Users/x/-acite _1660463321N.html /Users/x/-acite _1612414441N.html /Users/x/fix _1660399672N.html /Users/x/fix _1660398829N.html /Users/x/water witching _1660460617N.html /Users/x/water witching _1660388149N.html /Users/x/water witching _1632222441N.html /Users/x/water witching _1660003224N.html
期望结果
/Users/x/-acite _1660475490N.html /Users/x/fix _1660399672N.html /Users/x/water witching _1660460617N.html
尝试的Perl命令
- 命令1:
find . -type f -exec perl -pi -w -e 's/(.*)(\R)(.*)(\R)/$1$2/' \{\} \;
- 命令2:
find . -type f -exec perl -pi -w -e 's/(.*?)(\R)(.*?)(\R)/$1$2/g;' \{\} \;
失败原因
- 逻辑偏离需求核心:你的正则只关注“相邻两行”的替换,完全没考虑到需求是按空白行分组,每组仅保留首行的结构,无法识别“同组多行+空白行分隔”的段落。
- 逐行处理模式限制:
perl -pi默认是逐行读取文件,当前行内容里没有后续行的换行符,导致正则里的\R根本无法匹配到两行的内容,自然不会执行替换。 - 命令自身的缺陷:
- 命令1不带
g修饰符,每次仅替换一次,只能删掉第二行,同组内的其他行完全处理不到,还会错误匹配跨组的行; - 命令2加了
g修饰符后,会全局配对删除相邻行,最后留下的是第1、3、5...行,完全不符合“每组留首行”的要求。
- 命令1不带
如果要实现需求,可以用Perl的段落模式处理,比如:
find . -type f -exec perl -00 -pi -e 's/^(.+\R).+/$1/s' {} \;
-00开启段落模式,将空白行分隔的内容作为一个整体读取;- 正则
^(.+\R).+匹配段落的第一行(含换行),s修饰符让.能匹配换行,最终把整个段落替换成首行。
内容的提问来源于stack exchange,提问作者user19770839
相关产品推荐
相关产品推荐

