Fazer um localizar e substituir entre duas cadeias de caracteres, através de várias linhas

0

Ok, então o que eu preciso fazer é converter todos os blocos de comentários deste formato:

/**
 *
 */

Para:

/*!

 */

Mas com uma ressalva adicional de que a linha após o /** não pode conter "Copyright", porque precisamos preservar a formatação da licença clichê.

Eu sinto que isso é possível com o regex com bastante facilidade, mas eu não sei muito sobre grupos de captura, e porque eu preciso fazer duas substituições eu simplesmente não sei o que fazer. Eu estava atualmente hackeando uma (má) solução em Perl, mas não sei como fazer a substituição corretamente lá.

EDIT: Eu provisoriamente tenho: \/\*\*.*(?!Copyright)^\ *(?P<ast>\*).*(?=\*\/)//sm , que funciona para combinar com o que eu preciso, mas como faço para substituir apenas o grupo capturado?

    
por Bronze 03.08.2016 / 21:55

2 respostas

1

Enquanto uma única expressão regular de complexidade desconhecida poderia, sem dúvida, fazer o trabalho, mais fácil de entender e manter pode ser um analisador linha por linha, com a ressalva óbvia de que este é um analisador incorreto que pode ser facilmente confundido se comentar Cadeias semelhantes a expressões aparecem em partes sem comentários do código (provavelmente há um lexer disponível para o idioma no CPAN, ou veja Parse: : MGC para uma maneira um pouco mais formal de fazer esse tipo de coisa).

#!/usr/bin/env perl
use strict;
use warnings;

my @comment;

# read stuff from standard input or files on argument line, whatever
LINE: while (<>) {
  # assume this is a comment, start saving lines
  if (m{^\s*/\*\*}) {
    push @comment, $_;
    next LINE;
  }
  if (@comment) {
    push @comment, $_;

    # here things end, or so we hope...
    if (m{^\s*\*/}) {
      # not copyright means fixup of the saved comment block...
      if ($comment[1] !~ m/Copyright/) {
        $comment[0] =~ s{/\*\*}{/*!};
        if (@comment > 2) {
          for my $i (1..$#comment-1) {
            $comment[$i] =~ s{^(\s*)\*(\s)}{$1 $2};
          }
        }
      }
      # emit and reset
      print for @comment;
      @comment = ();
    }

    next LINE;
  }

  # hopefully only not-comment lines
  print;
}
    
por 03.08.2016 / 22:42
0

Assumindo os bloqueios de comentário e estão no início da linha (sem espaço antes de /** ), algo assim pode funcionar:

#!/usr/bin/awk -f
/^\/[*][*] Copyright/ {print; next}                      # 1
/^\/[*][*]/     { flag = 1; sub("^/[*][*] ", "/*! ") }   # 2
flag && /^ \* / { sub("^ [*]", "  ") }                   # 3
/ [*]\//        { flag = 0 } 1;                          # 4

(1) Se houver /** Copyright , apenas imprima e vá para a próxima linha. (2) Se houver outro /** , defina um sinalizador para marcar que estamos em um bloco de comentário e substitua por /*! , (3) se o sinalizador estiver definido, remova o asterisco do início da linha. (4) limpar o sinalizador se o comentário terminar (um */ é visto) e o 1 no final imprimirá a linha.

Teste:

$ cat comments 
/** foo
 *  bar
 */

 * This isn't a comment

/** Copyright
 *  isn't changed
 */

$ awk -f strip.awk comments 
/*! foo
    bar
 */

 * This isn't a comment

/** Copyright
 *  isn't changed
 */
    
por 03.08.2016 / 23:26