跨多行在两个字符串之间进行查找和替换

跨多行在两个字符串之间进行查找和替换

好的,那么我需要做的就是转换这种格式的所有注释块:

/**
 *
 */

到:

/*!

 */

但需要注意的是,后面的行/**不能包含“版权”,因为我们需要保留样板许可证格式。

我觉得使用正则表达式可以很容易地做到这一点,但我对捕获组不太了解,而且因为我需要进行两次替换,所以我不知道该怎么做。我目前正在 Perl 中破解一个(糟糕的)解决方案,但我不知道如何在那里正确地进行替换。

编辑:我暂时有:\/\*\*.*(?!Copyright)^\ *(?P<ast>\*).*(?=\*\/)//sm,它可以满足我的需要,但是如何仅替换捕获的组?

答案1

虽然复杂性未知的单个正则表达式无疑可以完成这项工作,但更容易理解和维护的可能是逐行解析器,但明显需要注意的是,这是一个糟糕的解析器,如果类似注释的字符串可能很容易被混淆出现在代码的非注释部分(CPAN 上可能有一个可用于该语言的词法分析器,或者参见解析::MGC以稍微正式的方式来做这些事情)。

#!/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;
}

答案2

假设注释块并且位于行的开头(之前没有空格/**),这样的事情可能会起作用:

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

(1) 如果有/** Copyright,则打印它并转到下一行。 (2) 如果有其他/**,设置一个标志来标记我们位于注释块中并替换为/*!, (3) 如果设置了该标志,则从行首删除星号。 (4) 如果注释结束(*/看到 a),则清除标志,并且1末尾的 打印该行。

测试:

$ 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
 */

相关内容