Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to delete empty Java comments like the following:

/**
*/

/*
 *
 *
 *
*/

I tried it with sed, but the following deletes all comments, not just the empty ones:

sed -r "/^\s*\/\*+\s*/,/\s*\*+\/\s*/d"

How can I tell sed to only delete ranges with lines of the shape \s\*+\s in between? I looked at http://www.grymoire.com/Unix/Sed.html#uh-29 but I didn't find the solution there.

P.S.: I created the following test file:

/**
bla bla bla
*/

/*ba dff
 *dd fdf
 *d f
 *df df df
*/

/**
*/

/*
 *
 *
 *
*/

class Test
{
 some code...
}

The first approach:

sed -n '/[^ \/\*]/p' /tmp/tmp

 bla bla bla
/*ba dff
 *dd fdf
 *d f
 *df df df
class Test
{
 some code...
}

One of the comment has its intro and outro stripped.

perl -0777 -pe 's,\s*/\*[*\s]*\*/\s*, ,gs' < /tmp/tmp

/**
bla bla bla
*/

/*ba dff
 *dd fdf
 *d f
 *df df df
*/  class Test
{
 some code...
}

The last comment is on the same line as the class definition.

warl0ck's approach:

$ removeemptycomments /tmp/tmp








class Test
{
 some code...
}
share|improve this question
add comment

5 Answers 5

sed works on one line at a time. Use perl instead:

perl -0777 -pe 's,\s*/\*[*\s]*\*/\s*, ,gs'

That will convert an empty comment and all the spaces around it to a single space (needed, otherwise int/* */i would be turned into inti otherwise for instance). Now, that means that if you have consecutive empty comments, you'll have consecutive white spaces, so you may want to change it to:

perl -0777 -pe 's,\s*(?:/\*[*\s]*\*/\s*)+, ,gs'

Now, to preserve spacing, it depends what you want to do, and how the comments are laid out. If the comments may be everywhere and you want to preserve indenting after a comment, but still want to condense unnecessary space, you could try:

perl -0777 -pe 's,(\s*)(?:\s*/\*[*\s]*\*/)+(\s*\n|\s*),"$1$2"=~/\n/?"\n":" ",ges'

That is, if there were newlines around the comments, replace with a newline (and the original indentation after a newline after the comments) or a space otherwise.

This is possible with perl because perl regexp alternation operator contrary to other regexp engine, don't try to find the longest match but look at each part of the alternation in turn until one matches.

Now, if you want to ignore empty comments that may occur inside strings (like "/***/"), it becomes a bit trickier especially when you have to take into account escaped double quotes or double quotes inside single quotes. But, once again the perl alternation regexp operator comes to the rescue:

perl -0777 -pe 's,(\s*)(?:\s*/\*[*\s]*\*/)+(\s*\n|\s*)|(/\*.*?\*/|//.*?\n|"(?:\\.|.)*?"|'\''(?:\\.)?.*?'\''|.[^"/'\'']*),"$3"or"$1$2"=~/\n/?"\n":" ",ges'

The idea is that that regexp matches the whole file, but in different alternatives of that big alternation that works a bit like a tokeniser.

Basically, it walks through the file and splits it into tokens. The text is considered as a sequence of tokens that are either the empty comments we're looking, ore double quoted strings, or single-quoted characters (with possibly escapes like '\'' or '\033'), or anything else.

Tokens that are the empty comments we're looking for are replaced with space or newline as above, anything else is replaced with itself. So it should now be able to process inputs like

/* comments with " unmatched quotes ' */ /* */
  f('"', "/***/" /***/, "\"", "/****/")

correctly. Now, not being familiar with the java syntax, I suppose there might be corner cases where that doesn't work, so a java expert would be able to improve it (for instance, in C, you'd need to account for trigraphs or backslashes can be used to escape newlines, so it would miss a /* that has been broken in the middle as /\<LF>*, it might be the same in java, so you could improve that code to take that into account).

share|improve this answer
    
This one works for me but deletes some newlines that I don't want to. –  kirdie Oct 22 '12 at 12:53
    
+1, to delete only comments just remove \s* from pattern : perl -0777 -pe 's,/\*[*\s]*\*/, ,gs' –  Nahuel Fouilleul Oct 22 '12 at 15:00
    
Actually sed can work on multiple lines ... just complicated –  warl0ck Oct 22 '12 at 15:44
    
@warl0ck, yes, though that number is limited in most sed implementations, POSIX only requiring the pattern and hold space to be able to hold 10 x LINE_MAX characters, where LINE_MAX, IIRC can be as little as 2048. So, in the general/portable case, sed is not appropriate for multiline handling. –  Stéphane Chazelas Oct 22 '12 at 16:20
    
Good, as long as there's no /* or */ in a string... –  Gilles Oct 22 '12 at 22:23
show 2 more comments

Trying to print the expected instead of deleting which is simpler in this case:

sed -n '/[^ \/\*]/p' file

This tries to print all those lines which contain anything other than / , space or a *

share|improve this answer
    
By the way, it will destroy the code in case non-empty comment starts with /* line or ends with */ line. –  rush Oct 22 '12 at 12:27
    
@rush : it wont.. non-empty comment contains something other than a slash, asterik or a space..so, this solution should work fine.. –  Guru Oct 22 '12 at 12:34
    
it will. Unfortunately I'm not able to make multiline message here in comments. I mean multiline comments like: 1st string: /* 2nd string * comment and last one */. With your code 1st and last one will be deleted, but middle one will stay. –  rush Oct 22 '12 at 12:46
    
This didn't work for me, it removed /**\n bla bla bla\n */ –  kirdie Oct 22 '12 at 12:50
    
@rush : got your point...yes, its incorrect,the middle one will stay... –  Guru Oct 22 '12 at 13:01
show 1 more comment
sed '/\/\*/{:a;N;/\*\//!ba};/^\s*\/\*\+[*\s\n ]*\*\/\s*$/d'

where

/\/\*/{:a;N;/\*\//!ba}

will append all comments string into one

/^\s*\/\*\+[*\s\n ]*\*\/\s*$/d

will check if it is empty comment and delete it if it is.

share|improve this answer
add comment

Here's something I found on internet few years ago, works for multiple lines,

#!/bin/sed -f
# if no /* get next
/\/\*/!b
# here we've got an /*, append lines until get the corresponding
# */
:x
/\*\//!{
N
bx
}
# delete /*...*/
s/\/\*.*\*\///
share|improve this answer
    
At least compared to the other sed answers, the syntax is standard. However, it doesn't answer the question (it removes all comments not only the empty ones), and won't work properly if there are multiple comments per line. –  Stéphane Chazelas Oct 23 '12 at 17:17
add comment

While this is possible with sed, it is complicated to recognize multiline comments, especially if you want to be careful and correctly handle /* or */ inside a literal string or a // comment.

Source files are typically small enough to fit completely in memory by a large margin, so there is no benefit in processing them line by line. Load the entire file in memory with a language such as Perl and Python, then do a partial tokenization. Here's a minimally untested Perl program.

perl -0777 -ne '
    while ($_ ne "") {
        if (s~\A[^/"]+|\A\x27\\?.\x27|\A"(?:[^\\"]|\\.")~~) { print $&; } # not a comment
        elsif (s~\A//(.*)$~~m) { $c = $&; print $c if $1 =~ /\S/ } # // comment
        elsif (s~\A/\*(.*?)(\*/|\z)~~) { # /*comment*/
            $c = $&;
            if ($1 =~ /\A[^\n\t *]/ || !$2) {
                print $c; # non-empty or non-terminated comment
            } else {
                $c =~ s/[^\n]//g; # empty comment: retain the newlines
                print $c;
            }
        } else {s~\A.~~; print $&;}
    }

'

share|improve this answer
    
@sch Copy-pasted? No, typed directly in my browser and completely untested. –  Gilles Oct 23 '12 at 12:01
    
it's getting there, but there still are a few issues (missing * inside quotes, missing a few s flags to substitutions at least). I'd be quite impressed if you could come up with a solution without testing it. –  Stéphane Chazelas Oct 23 '12 at 14:11
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.