Reputation: 3326
I'm attempting to write a very basic shell to python converter, and I'm having some trouble replacing variables. Example, I want:
echo $var1 $var2 $var3
echo $var1 $var2 $var3 $var4
to become:
print var1, var2, var3
print var1, var2, var3, var4
currently, it becomes:
print var1, var2 var3
print var1, var2 var3, var4
My regex is:
$string =~ s/(\$[a-z]+[a-z0-9]*)(\s+\S+)/$1,$2/gi;
for some reason, it doesn't apply the regex again to the second part of the matched string, even though the global modifier is set.
Very thankful for any help!
Upvotes: 1
Views: 838
Reputation: 139531
Make your substitution conditional on whether the variable occurs at the end of the line with
$string =~ s{\$([a-z]+[a-z0-9]*)(\s*$)?}{ defined $2 ? $1 : "$1," }ge;
The subpattern that corresponds to $2
is (\s*$)?
. The ?
makes the match optional, so $2
will be defined only when that pattern matches successfully, that is, for the last variable on the line—even in the presence of invisible trailing whitespace. For an “interior” variable, append a comma to the end. Otherwise, the variable name only will do.
For example
#! /usr/bin/env perl
use strict;
use warnings;
while (defined(my $string = <DATA>)) {
$string =~ s{\$([a-z]+[a-z0-9]*)(\s*$)?}{ defined $2 ? $1 : "$1," }ge;
$string =~ s/\becho\b/print/g; # for demo only
print $string, "\n";
}
__DATA__
echo $var1 $var2 $var3
echo $var1 $var2 $var3 $var4
Output:
print var1, var2, var3 print var1, var2, var3, var4
Upvotes: 0
Reputation: 2277
Keeping close to your regex, try this:
use strict;
use warnings;
my $string = '$var1 $var2 $var3 $var4$var5';
$string =~ s/\$([a-z][a-z0-9]*)\s*/$1, /gi;
$string =~ s/,\s*$//; #removing trailing comma
print $string . "\n";
Output:
var1, var2, var3, $var4
Or I would simply do this, which may or may not work with some other things you may have.
s/\$(\w+)\s*/$1, /g
Upvotes: 1
Reputation: 3631
Once it has matched the the (\s+\S+) the regex engine has moved passed the 2nd variable. A lookahead assertion will allow it to check what is ahead without consuming the string
$string =~ s{
\$
( [a-z]+[a-z0-9]* ) # capture varname
(?=\s+\S+) # lookahead
} {$1,}gix ;
Note that I am neither matching nor capturing the \s+S+ so no need to include it as $2 in the replacement string. And the /x allows me to space the regex out and add add comments.
Note - other answers may give a closer match to what you are tring to do. I am just explaining your specific query about not matching the 2nd variable.
Upvotes: 0
Reputation: 9029
You would just need to modify your regex to:
$string =~ s/\$([a-z][a-z0-9]*)(?:\s*|$)/$1, /gi;
$string =~ s/,\s*$//; #courtesy Hameed
The non capturing group would ensure that the variable ends either with a space, or no space at all or would be at the end of the line.
This would also match echoes like $var1 $var2 $var3 $var4$var6
and output var1, var2, var3, var4, var5, var6
Upvotes: 0