Brinck
Brinck

Reputation: 69

Using gawk or sed to inplace change line after or before every other match

I am trying to change the comment format for many files. Currently I have

//-----------------------------------------------------------
//   NAME : Class
//   DESCRIPTION : Vague information
//-----------------------------------------------------------

The number of - may be different with each file, or even with each case. I would like something like this to keep readability with the rest of the code while still allowing compatibility with a documenting program:

//-----------------------------------------------------------
/*!
//   NAME : Class
//   DESCRIPTION : Vague information
*/
//-----------------------------------------------------------

But this is also acceptable, and for sure easier:

/*!
//   NAME : Class
//   DESCRIPTION : Vague information
*/

For a start, I have tried something like

$ gawk -i inplace '/^\/\/--.*/&&v++%2 {sub(/^\/\/--.*, "\/\*!")}' filename.cpp and then $ gawk -i inplace '/^\/\/--.*/{sub(/^\/\/--.*, "\*\/")}' filename.cpp

which obviously has some syntax errors; the goal was to change every odd instance of //---* with /*!, and then replacing //---* with */, and for just one file, instead of many .cpp and .h/.hpp files.

Upvotes: 3

Views: 180

Answers (6)

potong
potong

Reputation: 58488

This might work for you (GNU sed):

sed '/^\/\/-\+$/{:a;N;/\n\/\/-\+$/!ba;s/\n.*\n/\n\/*!&*\/\n/}' file

Gather up lines that start and end //----------....

Prepend \n/*! and append */\n between the first and last newline of the collection.

Or if prefered:

sed '/^\/\/-\+$/{:a;N;/\n\/\/-\+$/!ba;s/^[^\n]*/\/*!/;s/\(.*\n\).*/\1*\//}' file

A "belt a braces" version of the first solution, that only applies to lines that begin and end as OP example with all lines commented inbetween:

sed '/^\/\/-\+$/{:a;N;/\n\/\/[^\n]*$/!{:b;P;D}
     /\n\/\/-\+$/!ba;s/\n.*\n/\n\/*!&*\/\n/;Tb}' file

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 204258

Using any awk:

$ awk '/^\/\/-+$/{ $0=( ++c%2 ? "/*!" : "*/" ) } 1' file
/*!
//   NAME : Class
//   DESCRIPTION : Vague information
*/

or if you prefer:

$ awk '/^\/\/-+$/{ $0=( ++c%2 ? $0 ORS "/*!" : "*/" ORS $0 ) } 1' file
//-----------------------------------------------------------
/*!
//   NAME : Class
//   DESCRIPTION : Vague information
*/
//-----------------------------------------------------------

To change the input file, if you have GNU awk change awk to awk -i inplace or with any awk add >tmp && mv tmp file at the end.

Upvotes: 0

Daweo
Daweo

Reputation: 36680

I would harness GNU AWK for this task following way, let file.txt content be

//-----------------------------------------------------------
//   NAME : Class
//   DESCRIPTION : Vague information
//-----------------------------------------------------------

then

awk 'index($0,"//---")==1{++v;if(v%2){print;print "/*!"}else{print "*/";print};next}{print}' file.txt

gives output

//-----------------------------------------------------------
/*!
//   NAME : Class
//   DESCRIPTION : Vague information
*/
//-----------------------------------------------------------

Explanation: for lines starting with //--- (I use index String function to avoid need to escape /) I do increase v by 1 and then print current line followed by /*! in case v is odd else print */ followed by current line, then I instruct GNU AWK to go to next line to avoid duplicate printing, all others lines are just printed. After you are sure result is compliant with requirement you might add -i inplace after awk.

(tested in GNU Awk 5.0.1)

Upvotes: 0

zdim
zdim

Reputation: 66924

perl -0777 -wnE'
    say s{ //-+\n\K (//.*?) (//-+\n) }{/*!\n$1*/\n$2}sgrx
' file_with_comment_blocks.txt

Broken into lines only for readability. Modifiers (at the end of regex) are:

  • s with it the . matches a newline as well

  • g repeat throughout the whole string ("global")

  • r so to return the new string (or the unchanged original). Used here for printing

  • x ignore spaces, so use them for readability (also allows newlines and #-comments)

This only prints so it can be redirected to a file for a result while it is safe for testing.

Or, change so to rewrite the file in-place

perl -0777 -i.bak -wnE'
    s{ //-+\n\K (//.*?) (//-+\n) }{/*!\n$1*/\n$2}sgx
' file_with_comment_blocks.txt

If backup isn't wanted then use -i (no .bak). See Command-line switches in perlrun

Upvotes: 2

sseLtaH
sseLtaH

Reputation: 11237

Using sed

$ sed -E 'N;s~-\n~&/*!\n~;s~\n/+-~\n*/&~' input_file
//-----------------------------------------------------------
/*!
//   NAME : Class
//   DESCRIPTION : Vague information
*/
//-----------------------------------------------------------

Upvotes: 2

dawg
dawg

Reputation: 104062

Given:

$ cat file
//-----------------------------------------------------------
//   NAME : Class
//   DESCRIPTION : Vague information
//-----------------------------------------------------------

With THIS regex, you can use perl:

$ perl -0777 -pE 's/^(\/\/-+\R)(\/\/[\s\S]*?)(^\/\/-+\R?)/\1\/\*!\n\2\*\/\n\3/gm' file 
//-----------------------------------------------------------
/*!
//   NAME : Class
//   DESCRIPTION : Vague information
*/
//-----------------------------------------------------------

Perl also has an inplace option.

Upvotes: 3

Related Questions