【问题标题】:How to compress 4 consecutive blank lines into one single line in Perl如何在 Perl 中将 4 个连续的空白行压缩为一行
【发布时间】:2012-09-07 21:51:21
【问题描述】:

我正在编写一个 Perl 脚本来读取日志,以便通过删除空行来将文件重新写入新日志,以防看到任何连续的 4 个或更多空行。换句话说,我必须将任意 4 个连续的空白行(或更多行)压缩成一行;但文件中任何 1、2 或 3 行的情况都必须保持格式。我试图在网上找到解决方案,但我唯一能找到的是

perl -00 -pe ''

perl -00pe0  

另外,我在 vim 中看到这样的示例删除 4 个空行块 :%s/^\n\{4}// 与我正在寻找的内容相匹配,但它是在 vim 而不是 Perl 中。有人可以帮忙吗?谢谢。

【问题讨论】:

  • “空行”是指“只有一个换行符”还是“只有空白字符”?

标签: perl


【解决方案1】:

要将 4+ 个连续的 Unix 样式 EOL 折叠到一个换行符:

$ perl -0777 -pi.bak -e 's|\n{4,}|\n|g' file.txt

另一种使用look-behind的风格:

$ perl -0777 -pi.bak -e 's|(?<=\n)\n{3,}||g' file.txt

【讨论】:

  • 嗨 Zaid,我使用你的第一个命令 "perl -0777 -pi.bak -e 's|\n{4,}|\n|' file.txt" 如果空格出现在文本中间,它能够删除空格。但是,该命令无法摆脱最后一行文本之后的空格。我可以知道如何解决这个问题吗?在最后的文本之后,我还有几百行空行。谢谢。
  • @Grace :我的猜测是您的“空行”在文件末尾不是空的,而是包含空格。您可以通过在文本编辑器中切换特殊字符来确认这一点。
  • 不,这是因为正则表达式没有启用多个替换的/g 开关。如果没有/g(或本例中的|g),则仅替换第一个匹配项。
  • 感谢 Zaid 和 Memowe。
【解决方案2】:
use strict;
use warnings;

my $cnt = 0;

sub flush_ws {
  $cnt = 1 if ($cnt >= 4);
  while ($cnt > 0) {print "\n"; $cnt--; }
}

while (<>) {
  if (/^$/) {
    $cnt++;
  } else {
    flush_ws();
    print $_;
  }
}
flush_ws();

【讨论】:

  • 您的解决方案没有正确考虑输入文件末尾的空行。
  • 您好 Perreal、Moritz Bunkus 和 TLP,非常感谢您的帮助,但我终于根据我能理解的最简单的答案得到了我的问题答案。
【解决方案3】:

您的-0 提示是一个很好的提示,因为您可以使用-0777-p 模式下吞食整个文件。在perlrun 中阅读更多关于这些人的信息,所以这个 oneliner 应该可以解决问题:

$ perl -0777 -pe 's/\n{5,}/\n\n/g'

如果连续最多有四个新行,则不会发生任何事情。五个换行符或更多(四个空行或更多)被两个换行符(一个空行)替换。注意这里的/g 开关不仅要替换第一个匹配项。

解析代码:

BEGIN { $/ = undef; $\ = undef; }
LINE: while (defined($_ = <ARGV>)) {
    s/\n{5,}/\n\n/g;
}
continue {
    die "-p destination: $!\n" unless print $_;
}

HTH! :)

【讨论】:

  • @Zaid 更快。对不起,重复。我们的解决方案使用不同的\n 计数 - 我以这种方式解释了这个问题,但更改正则表达式对于@Grace 来说是一个简单的练习。 ;)
  • 嗨 Memowe,感谢您的建议,我正在使用您在该行中建议的第一个命令(与 Zaid 相同)。我可以知道 -pe 是什么,以及作为 Zaid 使用的命令行的含义,只有 -e。当我回复 Zaid 时,该命令实际上可以很好地消除文本行之间的空格,但如果空格发生在最后一行文本之后,则不能。你知道如何解决这个问题吗?
  • @Grace:请咨询perlrun 以获得完整的-p 解释。它使用最终的print 启用while 循环,@Zaid 在他的解决方案中也有它,在-pi.bak 中。 -i.bak 用于使用带有.bak 文件扩展名的备份副本进行就地替换。我刚刚检查了一下,我很确定我的版本替换了文件末尾的空行,因为它使用了/g
  • 感谢 Memowe,我终于将 Zaid 和您的解决方案结合起来完成了我的工作。如果我只使用 -pe 而没有 -i.bak 选项(perl -0777 -pe 's/\n{5,}/\n\n/g' file.txt),它会以某种方式无法获得结果。我终于通过这个命令完成了它:-perl -0777 -pi.bak -e 's/\n{4,}/\n\n/g file.txt
  • 如果没有 -i 输出到 STDOUT,您可以使用 $ perl ... &gt; new_file 捕获它。 HTH。
【解决方案4】:

一种使用GNU awk的方式,将记录分隔符设置为NUL:

awk 'BEGIN { RS="\0" } { gsub(/\n{5,}/,"\n")}1' file.txt

这假设您定义的是空的不包括空格

【讨论】:

  • 感谢史蒂夫的帮助。
【解决方案5】:

这将满足您的需要

perl -ne 'if (/\S/) {$n = 1 if $n >= 4; print "\n" x $n, $_; $n = 0} else {$n++}' myfile

【讨论】:

  • 感谢鲍罗丁的帮助。
猜你喜欢
  • 1970-01-01
  • 2021-03-13
  • 2015-12-29
  • 1970-01-01
  • 2023-03-20
  • 2017-12-25
  • 2011-02-22
  • 2012-04-30
  • 1970-01-01
相关资源
最近更新 更多