使用 perl 或任何其他工具进行多行编辑

使用 perl 或任何其他工具进行多行编辑

我正在编辑我的.uncrustify.cfg文件以使其更具可读性。我只想像这样重新格式化:

两行:

# Add or remove between the parens in the function type: 'void (*x)(...)'
sp_after_tparen_close      = ignore   # ignore/add/remove/force

一行出:

sp_after_tparen_close      = ignore   # ignore/add/remove/force#   Add or remove between the parens in the function type: 'void (*x)(...)'

Perl 似乎是最佳选择,但其语法让我不知所措。当我有空闲的十年时,我会学习它;-)

为了使其更通用一些:

两行:

#a comment line
some code

一行出:

some code # a comment line

==========================

约翰:手工完成的两行:

nl_while_brace             = ignore   # I,A,R,F     # Add or remove newline between 'while' and '{'
nl_scope_brace             = ignore   # I,A,R,F     # Add or remove newline between 'scope (x)' and '{' (D)

...没有使用 awk 组合的两对:

# Add or remove newline between 'unittest' and '{' (D)
nl_unittest_brace          = ignore   # I,A,R,F

# Add or remove newline between 'version (x)' and '{' (D)
nl_version_brace           = ignore   # I,A,R,F

答案1

sed '/^#/N;s/\(.*\)\n\([^#].*\)/\2 \1/;P;D'

这将处理问题中的简单示例 - 任何注释行后跟的不是注释且至少包含一个字符的行将被附加到其后面的行。

因此,运行您的示例,输出为:

sp_after_tparen_close      = ignore   # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)'

通过它运行 @John1024 的示例,输出为:

#
# Some comments
#

sp_after_tparen_close      = ignore   # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)'

some code #a comment line
more code

# comment one
# comment two
still more code # comment three

要处理此类情况,sed无需循环。在这种情况下,唯一可能包含\newline 字符的行是以散列开头的行,#因为这些行是唯一sed要添加 1 的行。

sed遇到以散列开头的行时,#它会拉入Next 输入行并将其附加到模式空间。sed然后尝试s///替换:

  • \(.*\)- 尽可能多地引用,\1紧随其后...
  • \n- 换行符紧接着...
  • \([^#].*\)- 至少有一个不是散列的字符#以及模式空间中剩余的所有内容......
  • \2 \1

sed然后P将模式空间打印到第一个出现的\newline 字符并D删除相同的内容,然后重新开始尝试剩余的内容(如果有的话)

答案2

我相信这可以满足您的要求:

awk '/^[[:space:]]*[^#]/ && last ~ /^#/ {printf "%s %s",$0,last; last="";next} {print last; last=$0} END{print last}' sample.cfg

举个例子,假设我们有这个输入文件:

#
# Some comments
#

# Add or remove between the parens in the function type: 'void (*x)(...)'
sp_after_tparen_close      = ignore   # ignore/add/remove/force

#a comment line
some code
more code

# comment one
# comment two
# comment three
still more code

输出是:

$ awk '/^[[:space:]]*[^#]/ && last ~ /^#/ {printf "%s %s",$0,last; last="";next} {print last; last=$0} END{print last}' uncrustify.cfg

#
# Some comments
#

sp_after_tparen_close      = ignore   # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)'

some code #a comment line
more code

# comment one
# comment two
still more code # comment three

怎么运行的

awk隐式循环文件中的每一行。

此脚本使用单个变量,last用于保存上一行。简而言之,当我们遍历每一行时,如果最后一行是注释而当前行不是,那么我们会将这两行一起打印出来。否则,我们会打印出最后一行。

  • /^[[:space:]]*[^#]/ && last ~ /^#/ {printf "%s %s",$0,last; last="";next}

    如果 (a) 此行不是注释,并且 (b) 上一行(最后一行)是注释,则将最后一行和当前行合并并打印出来。之后,last就可以清空了。然后,跳过其余命令并跳转到重新开始next

  • {print last; last=$0}

    否则,打印该last行。last使用当前行的内容进行更新。

  • END{print last}

    循环完文件中的所有行后,打印该last行的内容。

另一个例子

考虑这个输入:

# Add or remove newline between 'unittest' and '{' (D)
nl_unittest_brace          = ignore   # I,A,R,F

# Add or remove newline between 'version (x)' and '{' (D)
nl_version_brace           = ignore   # I,A,R,F

输出是:

$ awk '/^[[:space:]]*[^#]/ && last ~ /^#/ {printf "%s %s",$0,last; last="";next} {print last; last=$0} END{print last}' new

nl_unittest_brace          = ignore   # I,A,R,F # Add or remove newline between 'unittest' and '{' (D)

nl_version_brace           = ignore   # I,A,R,F # Add or remove newline between 'version (x)' and '{' (D)

答案3

根据我的评论,在一个简短的脚本中开发这样的东西是最简单的,而不是摆弄命令行。另外,您可以保留它。

#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);

my $buffer = "";
my $linesBuffered = 0;

while (<STDIN>) {
# Check if this line is a just a comment.
    if ($_ =~ /^\s*#/) {
    # Assume multi-line comments should not be appended.
        if ($buffer) { $buffer .= $_ }
        else { $buffer = $_ }
        $linesBuffered++;
    } else {
        if ($linesBuffered > 1) {
        # Print multi-line comment.
            print "$buffer$_";
        # Reset buffer.
            $buffer = "";
            $linesBuffered = 0;
        } elsif ($buffer) {
        # Print buffered line with comment trailing.
            chomp $_;
            print "$_ $buffer";
        # Reset buffer.
            $buffer = "";
            $linesBuffered = 0;
        } else { print $_ }
    }
}

print $buffer if ($buffer);  

可以使用这个,例如./filter.pl < .uncrustify.cfg > .uncrustify.copy。请注意,这还没有到位,所以cp .uncrustify.copy .uncrustify.cfg如果您高兴的话,您必须稍后再做。由于它从标准输入读取,因此您可以测试它:

> ./filter.pl
what  <- stdin
what  <- stdout

这里它立即吐出该行,因为它不是评论。我不会在接下来的示例中指出 stdin 和 stdout。

#okay
then
then #okay

在这种情况下,它缓冲注释行并将其附加到下一个(非注释)行。

#foo
#bar
#foo
#bar

在这种情况下,它会输出多行注释。

几点:

  • 在 Perl 中,空字符串 ( "") 测试为 false。
  • /^\s*#/将匹配以零个或多个空格开头的行,然后是#.
  • 除非chomped,否则输入行末尾将有一个换行符。

以下是 John1024 示例的输出:

#
# Some comments
#

sp_after_tparen_close      = ignore   # ignore/add/remove/force # Add or remove between the parens in the function type: 'void (*x)(...)'

some code #a comment line
more code

# comment one
# comment two
# comment three
still more code

注意哪里# comment three这里与 John1024 和 mikeserv 的输出有关。这是有意为之,但其值取决于您的要求 - 这里我的偏好是假设多行注释的最后一行不应添加到下一行代码之前,即仅单线代码后面的注释被移动。完成此任务会增加脚本的复杂性;否则变量$linesBuffered和与之相关的逻辑就不是必需的。

相关内容