Can anyone explain me this regex meaning - regex

I would like to understand this expression meaning.
$req_msg =~ s/ \${$toReplace}/$replacements->{$toReplace}/g;

Prerequisite for this to work are two variables:
$toReplace - contains an arbitrary value
$replacements - a HASH ref containing, erm, replacements
Given $toReplace contains "foo", the contents of $req_msq are searched for ${foo} (with a leading single space) with every occurence of this being replaced with $replacements->{foo}.

$req_msg =~ s/ \${$toReplace}/$replacements->{$toReplace}/g;
s is used for substitution. $content=~ s/old_value/new_value/modifier; (modifier can be i, g, x, along or combination)
Ex:
$content = "Hi I am a coder and I like coding very much!";
$content =~ s/i/eye/i;
now $content will contain "Heye eye am a coders and eye like coding very much"
In the same way ${$toReplace} which simply means a scalar reference is the old value which needs to be replace and $replacements->{$toReplace} means $replacements is a hash reference whose key is $toReplace .
It is smiliar to $hash_value = hash_ref->{key};
whereever it finds the value returned by scalar reference , gets replace by hash reference's key with the corresponding value found in $req_msg
But I guess you asked this question because you got blank replacement. That may be due to scalar reference problem.
This code snippet may help in removing your doubt.
#!/usr/bin/perl
use strict;
use warnings;
my $value = "Jassi";
my $scalar_ref = \$value;
print "scalar_ref = $scalar_ref \n and value = $value and ${$scalar_ref}\n";
my %hash = ("Jassi", "aliencoders");
my $hash_ref = \%hash;
my $reg_msg = "Hi this is Jassi";
print "reg_msg = $reg_msg \n";
$reg_msg =~ s/${$scalar_ref}/$hash_ref->{${$scalar_ref}}/;
print "reg_msg after s = $reg_msg\n";
See the second last line!

It replaces every occurance of the text ${blabla} with whatever is stored in the hash reference $replacements with the key blabla, e.g.:
$replacements = { 'blabla' => 'blubb' };
will make every ${blabla} being replaced by blubb in $req_msg.

Related

perl regex error: Modification of a read-only value attempted

I have this perl script:
use strict;
use warnings;
foreach my $line (" ^?[?12;12A", " ^?[A") {
print "$line\n";
$line =~ s/\s?[[:cntrl:]]\[(\?)?([0-9]{1,2}(;[0-9]{1,2})?)?[a-zA-Z]//g;
print "$line\n";
}
Those are two strings that start with a space, then a control character, then some regular ascii characters. It results with this error:
$ perl foo.pl
[?12;12A
Modification of a read-only value attempted at foo.pl line 6.
$
What am I doing wrong?
In a foreach loop the loop variable ("topicalizer") is but an alias for the currently processed list element; by changing it we really change the element.
If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over.
The loop in the question iterates over a list of string literals, and those are read-only. Attempting to change that is a fatal error (perldiag) (this case, of foreach, is given as one example.
Some ways around this are shown in Hameed's answer, to store them in an array, or to assign the string literal to a variable first.
Or, use the "non-destructive" modifier on the substitution operator, s///r, which doesn't change the original but returns the changed value (or the original if it didn't change)
my $new_line = $line =~ s/.../.../r;
In your case $line is a read-only value.
You can fix this in two ways:
Work with an actual array like my #testarray = (" ^?[?12;12A", " ^?[A");
Assign the value of $line to another variable and modify that:
my $tmp = $line;
$tmp =~ s/\s?[[:cntrl:]]\[(\?)?([0-9]{1,2}(;[0-9]{1,2})?)?[a-zA-Z]//g;

$& not resolved as part of perl substitution

I have a perl script which searches and replaces data in multiple files. Since more than one word can be replaced in a file, I wrote a function that accepts the search and replace patterns as arrays. I then loop over the arrays in this function and perform the substitution. It works well but just for one particular file, I need to append something in front of the matched string( character #). Hence, I pass "#\$&" as my replace pattern. Its received properly but somehow the $& is never resolved. Instead the operation replaces the matched string with literal value of '#$&'. The same thing works if I directly use #$& in my substituion command in the readFile function. I know we may be able to achieve the result in other ways, but I really want to know why the same replacement pattern works when passed directly while it doesn't work when read as an array element.
I have commented the substitution command that works well for reference. Can anyone please help me spot the problem here ?
my #search= ("host\\s*(replication|all)");
my #replace= ("#\$&");
my $sLine = scalar #search;
my $rLine = scalar #replace;
my $data = ???;
for ( my $i=0; $i < $sLine; $i++)
{
print("\n search = $search[$i] replace = $replace[$i] \n");
#$data =~ s/$search[$i]/#$&/g; ==> this works
$data =~ s/$search[$i]/$replace[$i]/g; #==> this doesn't
}
print($data);
The difference between the working solution and the non-working solution is the same as the difference between
print "#$&"; # Prints `#` and the value of `$&`.
and
print "$replace[$i]"; # Prints the value of `$replace[$i]`.
You can use the following:
use String::Substitution qw( gsub_modify );
for my $i (0..$#search) {
gsub_modify($data, $search[$i], $replace[$i]);
}
This is a more in-depth explanation.
s/$search[$i]/#$&/g
is short for
s/$search[$i]/ "#$&" /eg
which is equivalent to
s/$search[$i]/ "#" . $& /eg # Replaces with `#` and the value of `$&`.
/e causes the replacement expression to be evaluated as Perl code, using its result as the replacement string.
On the other hand,
s/$search[$i]/$replace[$i]/g
is short for
s/$search[$i]/ "$replace[$i]" /eg
which is equivalent to
s/$search[$i]/ $replace[$i] /eg # Replaces with the value of `$replace[$i]`.

Search two perl regex and store in one declared variable

So this is the scenario:
I perform a perl regex search on a string and store it in a variable
I then want to retrieve a substring from that variable and save it under the same variable
When I try with two separate variables it works, but I would like to minimies my variable declaration. What currently works:
my ($temp1) = ($buildLog =~ /(build\_version.*\d*)/);
my ($buildVersion) = ($temp1 =~ /(\d.*)/);
print "$temp1\n"; #$temp1 contains: build_version = 1411450178
print "$buildVersion\n"; #$buildVersion contains: 1411450178
But when I try to do it with one variable it only prints out the 1 ie that it found the match, but I would like the actual value. See below:
my ($temp2) = ($buildLog =~ /(build\_version.*\d*)/);
$temp2 = ($temp2 =~ /(\d.*)/);
print "$temp2\n"; #$temp1 just prints out 1
Could anybody please provide a quick explination of the behaviour and if it is indeed possible to use only one variable to get the content of the search ?
Thanks,
CJ
Only one regex is needed:
use strict;
use warnings;
my $buildLog = 'foobar build_version = 1411450178 bazbiz';
my ($buildVersion) = $buildLog =~ /build_version\D*(\d+)/;
print "$buildVersion\n";
Outputs:
1411450178
This answer has the correct solution for what you are trying to do. I just wanted to provide a quick explanation of why your code is not working as you expect.
You are confusing scalar and list modes. Your code
$temp2 = ($temp2 =~ /(\d.*)/);
is taking the results of the match (in a list context) and assigning it to a scalar. This assigns the number of elements in the list to the scalar.
You could also have used
$temp2 = ($temp2 =~ /(\d.*)/)[0];
to pick up the first match result.
#jm666's answer works because it assigns the list of match results to a list of variables.
The following
my ($temp2) = ($buildLog =~ /(build\_version.*\d*)/);
($temp2) = ($temp2 =~ /(\d.*)/);
will print
1411450178

Whole word matching with unexpected insertion in data

I have string consider
my $string = 'String need to be evaluated';
in $string I'm searching evaluated or any other word.
problem is their may be insertion of some tags in string
eg. Str<data>ing need to be eval<data>ua<data>ted which is unexpected.
In this case how could I search for the words?
here is the code I tried:
my $string = 'Text to be evaluated';
my $string2 = "Te<data>xt need to be eval<data2>ua<data>ted";
# patten to match
$pattern = "evaluated";
#b = split('',$pattern);
for my $i(#b){
$i="$i"."\(?:<data>\)?";
print "$i#\n";
}
$pattern = join('',#b);
print "\n$pattern\n";
if ($string2 =~ /$pattern/){
print "$pattern found\n";
}
Do you suggest any other method or module to make it easy? i don't know what kind of data will get inserted.
Not sure if that is what you need but how about
#b = split('',$pattern);
for my $i(#b){
$i=$i.".*";
print "$i \n";
}
$pattern = join('',#b);
That should match any string that had the pattern before it got random insertions as long as the characters of the pattern are still there and in the correct order.
It does find evaluated in the string esouhgvw8vwrg355#*asrgl/\u[\w]atet(45)<data>efdvd what is about as noisy as it gets. But of course, if it is impossible to distinguish between insertion and original string, you will get "false" positives. For example if the string used to be evaluted and it becomes something like evalu<hereisyourmissinga>ted you will get a positive. Of course, if you knew that insertions would always be in tags while text is not, users answer is much safer.
As long as you single quote your input string, characters like [\w] (45) and whatnot should not hurt either. I cannot see why they would be interpolated at any point.
Of course, you could use regexp to do the job:
foreach my $s ($string,$string2){
my $cs= $s;
### canonize
$cs =~ s!<[^>]*>!!gs;
### match
if ($cs =~ m!$pattern!i){
print "Found $pattern in $s!\n";
}
}

Inline regex replacement in perl

Is there a way to replace text with a regex inline, rather than taking the text from a variable and storing it in a variable?
I'm a perl beginner. I often find myself writing
my $foo = $bar;
$foo =~ s/regex/replacement/;
doStuff($foo)
where I'd really like to write
doStuff($bar->replace(s/regex/replacement/));
or the like, rather than using a temporary variable and three lines.
Is there a way to do this? Obviously when the regex is sufficiently complicated it makes sense to split it out so it can be better explained, but when it's just s/\s//g it feels wrong to clutter the code with additional variables.
You really can't do what you want because the substitution function returns either a 1 if it worked or an empty string if it didn't work. That means if you did this:
doStuff($foo =~ s/regex/replacement/);
The doStuff function would be using either 1 or an empty string as a parameter. There is no reason why the substitution function couldn't return the resultant string instead of just a 1 if it worked. However, it was a design decision from the earliest days of Perl. Otherwise, what would happen with this?
$foo = "widget";
if ($foo =~ s/red/blue/) {
print "We only sell blue stuff and not red stuff!\n";
}
The resulting string is still widget, but the substitution actually failed. However, if the substitution returned the resulting string and not an empty string, the if would still be true.
Then, consider this case:
$bar = "FOO!";
if ($bar =~ s/FOO!//) {
print "Fixed up \'\$bar\'!\n";
}
$bar is now an empty string. If the substitution returned the result, it would return an empty string. Yet, the substitution actually succeeded and I want to my if to be true.
In most languages, the substitution function returns the resulting string, and you'd have to do something like this:
if ($bar != replace("$bar", "/FOO!//")) {
print "Fixed up \'\$bar''!\n";
}
So, because of a Perl design decision (basically to better mimic awk syntax), there's no easy way to do what you want. However you could have done this:
($foo = $bar) =~ s/regex/replacement/;
doStuff($foo);
That would do an in place setting of $foo without first assigning it the value of $bar. $bar would remain unchanged.
Starting from perl 5.14 you can use Non-destructive substitution to achieve desired behavior.
Use /r modifier to do so:
doStuff($bar=~s/regex/replacement/r);
use Algorithm::Loops "Filter";
# leaves $foo unchanged
doStuff( Filter { s/this/that/ } $foo );
You can use a do { } block to avoid creating a temporary variable in the current scope:
doStuff( do {(my $foo = $bar) =~ s/regex/replacement/; $foo} );
Is this what you want?:
my $foo = 'Replace this with that';
(my $bar = $foo) =~ s/this/that/;
print "Foo: $foo\nBar: $bar\n";
Prints:
Foo: Replace this with that
Bar: Replace that with that
There is yet another way: Write your own function:
sub replace (
my $variable = shift;
my $substring = shift;
eval "\$variable =~ s${substring};";
return $variable
}
doStuff(replace($foo, "/regex/replace/"));
This wouldn't be worth it for a single call, and it would probably just make your code more confusing in that case. However, if you're doing this a dozen or so times, it might make more sense to write your own function to do this.