0

Okay, so what I need to do is to convert all comment blocks of this format:

/**
 *
 */

To:

/*!

 */

But with an additional caveat that the line after the /** cannot contain "Copyright", because we need to preserve the boilerplate license formatting.

I feel like this is doable with regex quite easily, but I do not know much about capture groups, and because I need to do two replacements I just don't know what to do. I was currently hacking a (bad) solution in Perl, but I don't know how to do the replacement correctly there.

EDIT: I provisionally have: \/\*\*.*(?!Copyright)^\ *(?P<ast>\*).*(?=\*\/)//sm, which works to match what I need, but how do I replace only the captured group?

3
  • If next line is ` *` it is could not contain Copyright, is it?
    – Costas
    Commented Aug 3, 2016 at 21:05
  • No, the blocks are of the format such that a Copyright can and will appear on the same line as the *.
    – Bronze
    Commented Aug 3, 2016 at 21:06
  • It will be nice if you show example
    – Costas
    Commented Aug 4, 2016 at 21:06

2 Answers 2

1

While a single regular expression of unknown complexity could doubtless do the job, more easier to understand and maintain might be a line-by-line parser, with the obvious caveat that this is a bad parser that may easily be confused if comment-like strings appear in not-comment portions of the code (there's probably a lexer available for the language on CPAN, or see instead Parse::MGC for a slightly more formal way to do these sorts of things).

#!/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;
}
3
  • Your script works almost perfectly, except that for me it skips the first matching block after the boilerplate in the file, and I can't figure out why.
    – Bronze
    Commented Aug 3, 2016 at 21:22
  • Doh! I had not even noticed until now that the boilerplate actually ends with two asterisks, making this actually much easier...
    – Bronze
    Commented Aug 3, 2016 at 21:30
  • I really needed that example to get me going. I was trying to overcomplicate it and make perl do the whole thing, writing the files, etc., but I just used this in a bash for loop with fancy globstar (**) to fix all the comment blocks. No need to overcomplicate things!
    – Bronze
    Commented Aug 5, 2016 at 5:17
0

Assuming the comment blocks and are at the beginning of the line (no space before /**), something like this might work:

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

(1) If there's /** Copyright, just print it and go to next line. (2) If any other /**, set a flag to mark we're in a comment block and replace with /*!, (3) if the flag is set, remove the asterisk from the beginning of the line. (4) clear the flag if the comment ends (a */ is seen), and the 1 at the end prints the line.

Test:

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .