Regex replace special comments - regex

So few months ago one of my colleagues left. He used to comment all his code this way:
//----------------------------
// COMMENT
//----------------------------
private void func()...
So each comment, instead of using 1 line at most, uses 4 lines (including break line), which drives me crazy. I'm trying to create a Regex which I can remove this comment safely and replace it. The above code should like this way:
// COMMENT
private void func()...
I thought of just removing each one of the '//----------------------------' but it leaves me with many empty lines as well as break line between the comment and the actual line which to be described. Any help will be well appreciated.
EDIT
Note one:
Our project is written in Visual Studio
Note two: Some comments may contain more than 1 line of comment, example:
//----------------------------
// LINE 1 COMMENT
// LINE 2 COMMENT
//----------------------------

This expression matches your case and any 3 lines of comments where the first and the last ones have trailing -:
((\s|\t)*\/{2,})(.*[-]+)(\r?\n)((\1(.*)\4?)+)\4\1\3\4?
Try it here
And then you can replace it with:
\5 (or $5)
EDIT: for multi-line comments.

Here's a Regular Expression that you can use to strip out the excess (decorative) comment lines and convert these bulky comments into one-liners.
It also supports indentation and multi-line comments using this style:
//----------------------------
// LINE 1 COMMENT
// LINE 2 COMMENT
//----------------------------
private void func()...
Find:
(( |\t)*?\r\n)?( |\t)*?//-+(\r\n( |\t)*?// .+)+\r\n( |\t)*?//-+\r\n
Replace With:
\4
(Replace \4 with $4 if the replace failed)
Good luck!

Related

Regex: keep same pattern found multiple times in same line and replace line by appending single pattern in front

Is it possible with notepad++ (or maybe from linux bash shell) to create multiple lines from a pattern found , as many times as the pattern is found and also append single found pattern in the newly created line?
The multi pattern is val=[0-9]+
The single pattern is id=[a-zA-Z0-9]+
Example:
Input lines:
id=af2477,val=333,val=777
id=af3456,val=222,val=444,val=678
id=af3327,val=3234,val=123,val=701
Output lines:
id=af2477,val=333
id=af2477,val=777
id=af3456,val=222
id=af3456,val=444
id=af3456,val=678
id=af3327,val=3234
id=af3327,val=123
id=af3327,val=701
I have tried with 2 subgroups but it wont work. It will only replace the second group once:
find what:(id=[a-zA-Z0-9]+,)(val=[0-9]+,)*
replace:\n\1,\2
UPDATE: Both answers from Toto and Wiktor Stribiżew seem to do the job. Haven't tested them yet. I would still like to see how this can work with the use of Notepad++ (even if multiple steps are needed)
Since you also consider using Linux tools for this, an awk solution looks much more viable:
awk 'BEGIN{FS=OFS=","} /^id=[a-zA-Z0-9]+(,val=[0-9]+)*$/{
for(i=2; i<=NF; i++) {
print $1,$i
}; next;
}{print $0}' file > outfile
See the online demo.
Here, any line that matches ^id=[a-zA-Z0-9]+(,val=[0-9]+)*$ (i.e. matches the format of the lines you need to expand) is split the way you need with for(i=2; i<=NF; i++) {print $1,$i}; next;. Else, the line is written as is (print $0).
The BEGIN{FS=OFS=","} part sets the input and output field separator to a comma.
This perl one-liner does the job (output on STDOUT):
perl -anE '($id,$vals)=/(id=\w+),(.+)$/;say "$id,$_" for split/,/,$vals' file
id=af2477,val=333
id=af2477,val=777
id=af3456,val=222
id=af3456,val=444
id=af3456,val=678
id=af3327,val=3234
id=af3327,val=123
id=af3327,val=701
Explanation:
($id,$vals)=/(id=\w+),(.+)$/; # explode id and values for each line in input file
say "$id,$_" for split/,/,$vals # print id and each value
You can redirect the output to another file:
perl -anE '($id,$vals)=/(id=\w+),(.+)$/;say "$id,$_" for split/,/,$vals' file > outputfile
Or do the change in-place:
perl -i -anE '($id,$vals)=/(id=\w+),(.+)$/;say "$id,$_" for split/,/,$vals' file
It is possible, yet very complex to do that with one regular expression for which you are gonna have to use (?R) and conditional statements.
With multiple steps would be pretty simple. You can for instance do find and replace using the max number of val that you might have in the longest lines, such as, imagine 4 would be the largest number of val, then we'll have four of (,val=[^\r\n,]*) in our initial expression:
^(id=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)$
and replace that with four lines,
$1$2\n$1$3\n$1$4\n$1$5
---- ---- ---- ----
Demo for Step 1
For any additional step, we can simply remove one val and one line from the end of initial expression and replacement. For example, our expression would look like
^(id=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)$
in the second step, for which we'd replace it with:
$1$2\n$1$3\n$1$4
---- ---- ----
Demo for Step 2
In the third and final step, our expression has two vals,
^(id=[^\r\n,]*)(,val=[^\r\n,]*)(,val=[^\r\n,]*)$
and our replacement will have two lines:
$1$2\n$1$3
---- ----
Demo for Step 3
For the case exampled in the question, only two steps are required and the second and third expressions would likely work just fine.

Regex: Capture any (dynamic) amount of lines

I've been trying to match the following:
First Group:Line1,
Line2,
..
LineX
Second Group:Some_Sample_text
With this query:
First Group:(?<first_group>.+\n*\n)Second Group:(?<second_group>.*)
My main goal is to capture any amount of lines between Line1 and LineX (because I can't anticipate how many there'll be), but since there's no option to match the end of files I'll probably need to use the "\n" tokens. I've also tried with IF and THEN statements but I just can't get it to work.
Any ideas appreciated.
Here, we might want to design an expression that'd just pass newlines, such as
First Group:([\s\S]*)Second Group:(.*)
First Group:([\d\D]*)Second Group:(.*)
First Group:([\w\W]*)Second Group:(.*)
Demo 1
and we'd expand it to,
First Group:([\s\S]*)Second Group:([\s\S]*)
First Group:([\d\D]*)Second Group:([\d\D]*)
First Group:([\w\W]*)Second Group:([\w\W]*)
If our second group would have had multiple lines.
Demo 2
Advice
The fourth bird advises that:
You could make the charachter class non greedy to prevent over matching ([\s\S]*?)
which then the expression would become,
First Group:([\s\S]*?)Second Group:([\s\S]*)
for instance.
Demo 3

Deleting comments in a large file

I am trying to delete a bunch of comments that are all in the following format:
/**
* #ngdoc
... comment body (delete me, too!)
*/
I have tried using this command: %s/\/**\n * #ngdoc.\{-}*\///g
Here is the regex without the patterns: %s/pattern1.\{-}pattern2//g
Here are the individual patterns: \/**\n * #ngdoc and *\/
When I try my pattern in vim I get the following error:
E871: (NFA regexp) Can't have a multi follow a multi !
E61: Nested *
E476: Invalid command
Thanks for any help with this regexp nightmare!
Instead of trying to cram this into one complex regex, it's much easier to search for the start of a comment and delete from there on to the end of a comment
:g/^\/\*\*$/,/\*\/$/d_
This breaks down into
:g start a global command
/^\/\*\*$/ search for start of a comment: <sol>/**<eol>
,/^\*\/$/ extend the range to the end of a comment: <sol>*/<eol>
d delete the range
_ use the black hole register (performance optimization)
Your problem is you have \{-} followed by * which are the multis referenced in the error message. Quote the *:
%s/\/\*\*\n \* #ngdoc\_.\{-}\*\/\n//g
Using embedded newlines in the pattern is the wrong approach. You should instead use an address range. Something like:
sed '\#^/\*\*$#,\#^\*/$#d' file
This will delete all lines starting from one that matches /** anchored at column 1 to the line matching */ anchored at column 1. If your comments are well behaved (eg, no trailing space after /**), this should do what you want.
Try this using gc to be careful when deleting
%s/\v\/\*\*\n\s\*\s\#ngdoc\n((\s*\n)?(\s\*.*\n)?){-}\s?\*\///gc
Match comments like
/**
* #ngdoc
* ... comment body (delete me, too!)
*
*/
My approached consists of using a macro:
qa/\/\*\*<enter><shift-v>/\*\/<enter>d
qa ........ starts recording macro "a"
/\/\*\* ... searches for the comment beginning
<Enter> ... use Ctrl-v Enter
V ......... starts visual block (until...)
/\*\/ ..... end of your comment
<Enter> ... Ctrl-v Enter agai
d ......... it will delete selected area
In order to isert etc presse followed by the keyword you want.

Is it possible to write comments in Xtend-templates?

Is it possible to write comments inside an Xtend template? (for example in order to quickly comment out an IF-statement or anything)
Yes, that's possible. Use the toggle-comment action in Eclipse or type the prefix ««« manually, e.g as in ««« my comment in a template
You can use ««« for single line comments like Sebastian Zarnekow mentioned.
A drawback of this commenting style is that it also comments out the newline character at the end of this line. Sometimes that's exactly what you want, but sometimes it's not.
For example: The following code snippet ...
val x = '''
line 1
line 2 ««« my comment
line 3
line 4
'''
println(x)
... will print following output ...
line 1
line 2 line 3
line 4
Another way to comment is as if you would insert an expression and inside the expression («») you use a plain old java comment. : «/* comment */»
That way you can go on with you template in the same line, span multiple rows and you avoid the deleted newline character.
PS: You can insert the guillemets this way:
« with ALT holding down and then 1 7 4 on the num block
» with ALT holding down and then 1 7 5 on the num block
or you map a good key combination to the two chars in your IDE, e.g. CTRL+< and CTRL+>
comment in xtend-templates: 【Ctrl + /】

How to find only patterns that are not commented?

I have some code where the same condition ABC is used as part of an if clause, at the end of it (as a comment) and in obsolete sections (which I do not want to remove yet). An example could look like this:
if (ABC) //this is the only line that should be matched, this comment should not change the outcome of the search
{
lots of code
} // if (ABC)
//if (ABC)
// {
// lots of obsolete code
// } // if (ABC)
How can I tell vim to search for the pattern ABC only where is is not commented out via // occurring before it on the same line?
^.*\(\/\/\)\#!.*ABC did not work, because the .* are also fulfilled by // and ^\(\/\/\)\#!*ABC complains about "Nested *".
Any ideas?
Thank you
for the example in your question, this line works:
/\v(\/\/.*)#<!ABC
or without very magic:
/\(\/\/.*\)\#<!ABC