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이 최선의 선택인 것처럼 보였지만 구문에 압도당했습니다. 10년의 여유가 생기면 배우겠습니다 ;-)

좀 더 일반화하려면 다음과 같이 하세요.

두 줄:

#a comment line
some code

한 줄 출력:

some code # a comment line

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

John: 손으로 그린 ​​두 줄:

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 문자를 포함할 수 있는 유일한 줄은 해시로 시작하는 줄입니다. 왜냐하면 이 줄에 1이 추가되는 #유일한 줄이기 때문입니다.sed

sed해시로 시작하는 줄을 만나면 추가 입력 줄을 #가져와서 N패턴 공간에 추가합니다. 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*#/0개 이상의 공백으로 시작하고 뒤에 #.
  • ed가 아닌 이상 chomp, 입력 줄 끝에 개행 문자가 있을 것입니다.

다음은 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및 관련 논리가 필요하지 않습니다.

관련 정보