views:

162

answers:

5

I need a regular expression to uncomment a block of Perl code, commented with # in each line.

As of now, my find expression in the Eclipse IDE is (^#(.*$\R)+) which matches the commented block, but if I give $2 as the replace expression, it only prints the last matched line. How do I remove the # while replacing?

For example, I need to convert:

# print "yes";
# print "no";
# print "blah";

to

print "yes";
print "no";
print "blah";
+4  A: 

In most flavors, when a capturing group is repeated, only the last capture is kept. Your original pattern uses + repetition to match multiple lines of comments, but group 2 can only keep what was captured in the last match from the last line. This is the source of your problem.

To fix this, you can remove the outer repetition, so you match and replace one line at a time. Perhaps the simplest pattern to do this is to match:

^#\s*

And replace with the empty string.

Since this performs match and replacement one line at a time, you must repeat it as many times as necessary (in some flavors, you can use the g global flag, in e.g. Java there are replaceFirst/All pair of methods instead).

References

Related questions


Special note on Eclipse keyboard shortcuts

It Java mode, Eclipse already has keyboard shortcuts to add/remove/toggle block comments. By default, Ctrl+/ binds to the "Toggle comment" action. You can highlight multiple lines, and hit Ctrl+/ to toggle block comments (i.e. //) on and off.

You can hit Ctrl+Shift+L to see a list of all keyboard shortcuts. There may be one in Perl mode to toggle Perl block comments #.

Related questions

polygenelubricants
well , ^#\s* does solve it , but my intentions were to match it as a whole and replace all the #'s in a block , so that i could use find and replace for only certain commented blocks . If we repeat the capturing group , uncommenting a big block would be tedious if u dont use replace all , and if u replace all , some of the other blocks would be uncommented too... the main question is if i could avoid the # from being matched to the capturing group
MIkhail
I have been using the Eclipse shortcut , but was trying a regex so that i wouldnt hav to move my hands to the mouse. Finding and replacing through the keyboard :)
MIkhail
A: 

You need the GLOBAL g switch.

s/^#(.+)/$1/g

Byron Whitlock
He's uncommenting Perl, but he's not using Perl to do it.
masonk
+2  A: 

Search with ^#(.*$) and replace with $1

Gopi
+1  A: 

You can try this one: -

use strict;
use warning;
my $data = "#Hello#stack\n#overflow\n";
$data =~ s/^?#//g ;

OUTPUT:-

Hello

stack

overflow

Or

open(IN, '<', "test.pl") or die $!;
read(IN, my $data, -s "test.pl"); #reading a file
$data =~ s/^?#//g ;
open(OUT, '>', "test1.pl") or die $!; 
print OUT $data; #Writing a file
close OUT;
close IN;

Note: Take care of #!/usr/bin/perl in the Perl script, it will uncomment it also.

Nikhil Jain
A: 

In order to determine whether a perl '#' is a comment or something else, you have to compile the perl and build a parse tree, because of Schwartz's Snippet

whatever  / 25 ; # / ; die "this dies!"; 

Whether that '#' is a comment or part of a regex depends on whether whatever() is nullary, which depends on the parse tree.

For the simple cases, however, yours is failing because (^#(.*$\R)+) repeats a capturing group, which is not what you wanted.

But anyway, if you want to handle simple cases, I don't even like the regex that everyone else is using, because it fails if there is whitespace before the # on the line. What about

^\s*#(.*)$

? This will match any line that begins with a comment (optionally with whitespace, e.g., for indented blocks).

masonk