I want to do something like this
if(($Fifo[5]=~/T0int(\S+)/)&&($Fifo[6]=~/T0int(\S+)/)&&($1 ne $2))
{
<Do something>
}
How can I reference matches evaluated in two regexps ?
By $1 I meant match evaluated in the first regexp and $2 in the next.
my($first) = $Fifo[5] =~ /T0int(\S+)/;
my($second) = $Fifo[6] =~ /T0int(\S+)/;
if (defined($first) && defined($second) && $first ne $second)) { ⋯ }
or more cavalierly:
if (($Fifo[5] =~ /T0int(\S+)/)[0] ne ($Fifo[6] =~ /T0int(\S+)/)[0]) { ⋯ }
or even more cavalierly still:
if ( (my($first, $second) = "#Fifo[5,6]" =~ /T0int(\S+)/g )
&& $first && $second
&& $first ne $second)
{
⋯
}
Try something like this:
if( ($Fifo[5] =~ (/T0int(\S+)/)) && ($Fifo[6] =~ (/T0int(\S+)/)) && ($1 ne $2) )
Basically put parenthesis around regex to group them as $1, $2
Related
I have one query. I have to match 2 strings in one if condition:
$release = 5.x (Here x should be greater than or equal to 3)
$version = Rx (this x should be greater than or equal to 5 if $release is 5.3, otherwise anything is acceptable)
e.g. 5.1R11 is not acceptable, 5.3R4 is not, 5.3R5 is acceptable, and 5.4 R1 is acceptable.
I have written a code like this:
$release = "5.2";
$version = "R4";
if ( $release =~ /5.(?>=3)(\d)/ && $version =~ m/R(?>=5)(\d)/ )
{
print "OK";
}
How can I write this?
This is really a three-level version string, and I suggest that you use Perl's version facility
use strict;
use warnings 'all';
use feature 'say';
use version;
my $release = '5.2';
my $version = 'R4';
if ( $version =~ /R(\d+)/ && version->parse("$release.$1") ge v5.3.5 ) {
say 'OK';
}
In regex (?>) it means atomic grouping.
Group the element so it will stored into $1 then compare the $1 with number so it should be
if (( ($release =~ /5\.(\d)/) && ($1 > 3) ) && (($version =~ m/R(\d)/) && ($1 >= 3) ) )
{
print "OK\n";
}
I got the correct one after modifying mkhun's solution:
if ((($release =~ /5.3/)) && (($version =~ m/R(\d+)(.\d+)?/) && ($1 >= 5))
|| ((($release =~ /5.(\d)/) && ($1 > 3)) && ($version =~ m/R(\d+)(.\d+)?/)) )
{
print "OK\n";
}
I have a string of domain like below:
$string = 'https://code.google.com && http://mycode.com/data && times.com && https://thehindu.com';
I want to replace all domains except mycode.com with mycode.com/unknown
So the output of above string after applying regex should be:
https://mycode.com/unknown && http://mycode.com/data && mycode.com/unknown && https://mycode.com/unknown
I have tried below regex, but it changes http://mycode.com/data also:
$string =~ s/(?<!mycode)[a-z\.]+?\.(com|org|net)/mycode\.com\/unknown/g;
How should i modify my regex to not match mycode.com
$s =~ s{
( [a-z.]+\.(?:com|org|net) )
(?![a-z.])
}{
$1 eq "mycode.com" ? $1 : "mycode.com/unknown"
}xeg;
or
$s =~ s{
(?<![a-z.])
(?! mycode\.com (?![a-z.]) )
([a-z.]+\.(?:com|org|net) (?![a-z.])
}{mycode.com/unknown}xg;
Handles
mycoder.com
mycode.combo.com
mycode.combo
notmycode.com
foo.combo
You're really closed, instead of lookbehind, use lookahead:
my $string = 'https://code.google.com && http://mycode.com/data && times.com && https://thehindu.com';
$string =~ s~(?<![a-z.])(?!mycode)[a-z.]+\.(?:com|org|net)~mycode.com/unknown~g;
say $string;
Output:.
https://mycode.com/unknown && http://mycode.com/data && mycode.com/unknown && https://mycode.com/unknown
Try replacing the matching part of the regex by that :
(http:\/\/)?(?!(mycode\.|ycode\.|code\.|ode\.|de\.|e\.))[a-z\.]+?\.(com|org|net)
Please try something like this
$string =~ s/https?:\/\/([^\/\s]+)/$match=$1;($match!~\/mycode.com\/)?'https:\/\/mycode.com\/unknown':$match/eg;
(Ignoring url without http://... and using 3 non-scrolling lines)
my $s = 'https://code.google.com && ....'
$s =~ s!//(?=mycode.com($|[^.\w]))!\cA!g; # // -> CTR-A
$s =~ s!//(\S+)!//mycode.com/unknown!g;
$s =~ s!\cA!//!g; # CTR-A -> //
Basic idea:
protect/mark/save the special cases
substitute the general situations
put-back the specials
I want to do a global regex replace, where the replacement is conditional upon some logic that can't be put in a regular expression. For example:
while ( $var =~ /<IF OPERATOR="(.+?)" VALUE="(.+?)"\/>/g ) {
my $operator = $1;
my $value = $2;
if ( $operator eq 'true' && $hash{ $value } ) {
# replace the entire <IF/>
}
if ( $operator eq 'false' && ! $hash{ $value } ) {
# replace the entire <IF/>
}
}
How do I do the # replace bit? Thanks for any advice.
Your refusal to give any real data for this question, or to describe what changes you want, makes it very difficult to demonstrate the workability of a solution.
However it looks like you need an executable replacement, which has the /e modifier.
Take a look at this code. I have added another pair of parentheses to the regex so that the entire pattern is captured as well as the two attributes. The actual replacement string is put into $replacement and returned by the block.
$string =~ s{(<IF OPERATOR="([^"]+)" VALUE="([^"]+)"/>)}{
my $replacement = $1;
my $operator = $2;
my $value = $3;
if ( $operator eq 'true' and $hash{$value} ) {
$replacement = qq{<if state1="yes"/>};
}
elsif ( $operator eq 'false' and not $hash{$value} ) {
$replacement = qq{<if state1="no"/>};
}
$replacement;
}eg;
A lot of logic can be placed in regular expressions. For instance, there are conditional regular expressions, and you can execute Perl code in a regexp.
If you don't want to complicate the regexp, you can extract the offsets of the matches first, then splice them out with substr EXPR, OFFSET, LENGTH, ''.
But for the fun of using regexps, with named backreferences and s///e (evaluate the replacement), here is the code:
#!/usr/bin/perl -w
use strict;
my %hash = (
foo => 1,
bar => 0
);
my $var = '
<IF OPERATOR="true" VALUE="foo"/>
<IF OPERATOR="true" VALUE="bar"/>
<IF OPERATOR="false" VALUE="foo"/>
<IF OPERATOR="false" VALUE="bar"/>
';
$var =~
s`(<IF\s+OPERATOR="(?<operator>.+?)"\s+VALUE="(?<value>.+?)"/>)
`$+{operator} eq 'true' && $hash{ $+{value} } || $+{operator} eq 'false' && !$hash{ $+{value} }? 'replacement' : $1
`xeg;
print $var;
$var=$ARGV[0];
my %hash =(
a => 1,
b => 2
);
while ( $var =~ /<IF OPERATOR="(.+?)" VALUE="(.+?)"\/>/ ) {
my $operator = $1;
my $value = $2;
if ( $operator eq 'true' && $hash{ $value } ) {
$var =~ s/<IF OPERATOR="$operator" VALUE="$value"\/>/ReplacemenT/g;
}
if ( $operator eq 'false' && ! $hash{ $value } ) {
$var =~ s/<IF OPERATOR="$operator" VALUE="$value"\/>/RR/g;
}
}
print "$var\n";
on something like 'xxx<IF OPERATOR="true" VALUE="a"/>xxx' returns xxxReplacemenTxxx
In Perl, how to write a regular expression that replaces only up to N matches per string?
I.e., I'm looking for a middle ground between s/aa/bb/; and s/aa/bb/g;. I want to allow multiple substitutions, but only up to N times.
I can think of three reliable ways. The first is to replace everything after the Nth match with itself.
my $max = 5;
$s =~ s/(aa)/ $max-- > 0 ? 'bb' : $1 /eg;
That's not very efficient if there are far more than N matches. For that, we need to move the loop out of the regex engine. The next two methods are ways of doing that.
my $max = 5;
my $out = '';
$out .= $1 . 'bb' while $max-- && $in =~ /\G(.*?)aa/gcs;
$out .= $1 if $in =~ /\G(.*)/gcs;
And this time, in-place:
my $max = 5;
my $replace = 'bb';
while ($max-- && $s =~ s/\G.*?\Kaa/$replace/s) {
pos($s) = $-[0] + length($replace);
}
You might be tempted to do something like
my $max = 5;
$s =~ s/aa/bb/ for 1..$max;
but that approach will fail for other patterns and/or replacement expressions.
my $max = 5;
$s =~ s/aa/ba/ for 1..$max; # XXX Turns 'aaaaaaaa'
# into 'bbbbbaaa'
# instead of 'babababa'
And of course, starting from the beginning of the string every time could be expensive.
What you want is not posible in regular expressions. But you can put the replacement in a for-loop:
my $i;
my $aa = 'aaaaaaaaaaaaaaaaaaaa';
for ($i=0;$i<4;$i++) {
$aa =~ s/aa/bb/;
}
print "$aa\n";
result:
bbbbbbbbaaaaaaaaaaaa
You can use the /e flag which evaluates the right side as an expression:
my $n = 3;
$string =~ s/(aa)/$n-- > 0 ? "bb" : $1/ge;
Here's a solution using the /e modifier, with which you can use
perl code to generate the replacement string:
my $count = 0;
$string =~ s{ $pattern }
{
$count++;
if ($count < $limit ) {
$replace;
} else {
$&; # faking a no-op, replacing with the original match.
}
}xeg;
With perl 5.10 or later you can drop the $& (which has weird
performance complications) and use ${^MATCH} via the /p modifier
$string =~ s{ $pattern }
{
$count++;
if ($count < $limit ) {
$replace;
} else {
${^MATCH};
}
}xegp;
It's too bad you can't just do this, but you can't:
last if $count >= $limit;
My code...
$option = "[1]";
if ($option =~ m/^\[\d\]$/) {print "Activated!"; $str=$1;}
I need a way to drop off the square brackets from $option. $str = $1 does not work for some reason. Please advise.
To get $1 to work you need to capture the value inside the brackets using parentheses, i.e:
if ($option =~ m/^\[(\d)\]$/) {print "Activated!"; $str=$1;}
if ($option =~ m/^\[(\d)\]$/) { print "Activated!"; $str=$1; }
Or
if (my ($str) = $option =~ m/^\[(\d)\]$/) { print "Activated!" }
Or
if (my ($str) = $option =~ /(\d)/) { print "Activated!" }
..and a bunch of others. You forgot to capture your match with ()'s.
EDIT:
if ($option =~ /(?<=^\[)\d(?=\]$)/p && (my $str = ${^MATCH})) { print "Activated!" }
Or
my $str;
if ($option =~ /^\[(\d)(?{$str = $^N})\]$/) { print "Activated!" }
Or
if ($option =~ /^\[(\d)\]$/ && ($str = $+)) { print "Activated!" }
For ${^MATCH}, $^N, and $+, perlvar.
I love these questions : )