Is there a difference between ($ipAddrResult =~ /Regex/gm) and ($ipAddrResult =~ m/Regex/g) in perl string matching? When I google online I get explanation for second one and not the first one. The file I tried to edit has first condition.
The ms in different places mean different things.
Let's look at the second example first.
m// is the regular expression matching operator. As a shortcut, the m can be omitted, so
$foo =~ m/$pattern/;
is exactly the same as
$foo =~ /$pattern/;
The only time the m is required is if you want to use delimiters other than / for your pattern. You can do, for example
$foo =~ m!$pattern!;
or
$foo =~ m[$pattern];
and so on, but these all require the m to be there.
In the first example, the m after the regex is a modifier flag which tells the regex how to behave. The regex flags are documented in the perlre man page, which has this to say:
m -
Treat string as multiple lines. That is, change "^" and "$" from
matching the start or end of line only at the left and right ends of
the string to matching them anywhere within the string.
So this:
$foo =~ /$pattern/m;
is the same as this:
$foo =~ m/$pattern/m;
and the same as this:
$foo =~ m{$pattern}m;
In the expression
/Regex/gm
The "m" stands for multi-line matching. In the expression:
m/Regex/g
The "m" stands for "match" as opposed to a substitution, which looks like this:
s/Regex/replacement/g
Because matching (vs. substitution) is the default, you can generally leave off the "m/" from the start of the expression. In other words "m/Regex/g" is just a synonym for "/Regex/g".
Yes, m/regex/g is syntactically equivalent to just /regex/g. That is, it doesn't activate the /m flag at all. Compare to s/foo/bar/ which is not at all the same as s/foo/bar/s. The name m stands for "match" I believe.
Related
I need help to understand what below command is doing exactly
$abc{hier} =~ s#/tools.*/dfII/?.*##g;
and $abc{hier} contains a path "/home/test1/test2/test3"
Can someone please let me know what the above command is doing exactly. Thanks
s/PATTERN/REPLACEMENT/ is Perl's substitution operator. It searches a string for text that matches the regex PATTERN and replaces it with REPLACEMENT.
By default, the substitution operator works on $_. To tell it to work on a different variable, you use the binding operator - =~.
The default delimiter used by the substitution operator is a slash (/) but you can change that to any other character. This is useful if your PATTERN or your REPLACEMENT contains a slash. In this case, the programmer has used # as the delimiter.
To recap:
$abc{hier} =~ s#PATTERN#REPLACEMENT#;
means "look for text in $abc{hier} that matches PATTERN and replace it with REPLACEMENT.
The substitution operator also has various options that change its behaviour. They are added by putting letters after the final delimiter. In this case we have a g. That means "make the substitution global" - or match and change all occurrences of PATTERN.
In your case, the REPLACEMENT string is empty (we have two # characters next to each other). So we're replacing the PATTERN with nothing - effectively deleting whatever matches PATTERN.
So now we have:
$abc{hier} =~ s#PATTERN*##g;
And we know it means, "in the variable $abc{hier}, look for any string that matches PATTERN and replace it with nothing".
The last thing to look at is the PATTERN (or regular expression - "regex"). You can get the full definition of regexes in perldoc perlre. But to explain what we're using here:
/tools : is the fixed string "/tools"
.* : is zero or more of any character
/dfII : is the fixed string "/dfII"
/? : is an optional slash character
.* : is (again) zero or more of any character
So, basically, we're removing bits of a file path from a value that's stored in a hash.
This =~ means "Do a regex operation on that variable."
(Actually, as ikegami correctly reminds me, it is not necessarily only regex operations, because it could also be a transliteration.)
The operation in question is s#something#else#, which means replace the "something" with something "else".
The g at the end means "Do it for all occurences of something."
Since the "else" is empty, the replacement has the effect of deleting.
The "something" is a definition according to regex syntax, roughly it means "Starting with '/tools' and later containing '/dfII', followed pretty much by anything until the end."
Note, the regex mentions at the end /?.*. In detail, this would mean "A slash (/) , or maybe not (?), and then absolutely anything (.) any number of times including 0 times (*). Strictly speaking it is not necessary to define "slash or not", if it is followed by "anything any often", because "anything" includes as slash, and anyoften would include 0 or one time; whether it is followed by more "anything" or not. I.e. the /? could be omitted, without changing the behaviour.
(Thanks ikeagami for confirming.)
$abc{hier} =~ s#/tools.*/dfII/?.*##g;
The above commands use regular expression to strip/remove trailing /tools.*/dfII and
/tools.*/dfII/.* from value of hier member of %abc hash.
It is pretty basic perl except non standard regular expression limiters (# instead of standard /). It allows to avoid escaping / inside the regular expression (s/\/tools.*\/dfII\/?.*//g).
My personal preferred style-guide would make it s{/tools.*/dfII/?.*}{}g .
What is difference between /.../ and m/.../?
use strict;
use warnings;
my $str = "This is a testing for modifier";
if ($str =~ /This/i) { print "Modifier...\n"; }
if ($str =~ m/This/i) { print "W/O Modifier...\n"; }
However, I checked with this site for Reference not clearly understand with the theory
There's no difference. If you just supply /PATTERN/ then it assumes m. However, if you're using an alternative delimiter, you need to supply the m. E.g. m|PATTERN| won't work as |PATTERN|.
In your example, i is the modifier as it's after the pattern. m is the operation. (as opposed to s, tr, y etc.)
Perhaps slightly confusingly - you can use m as a modifier, but only if you put if after the match.
m/PATTERN/m will cause ^ and $ to match differently than in m/PATTERN/, but it's the trailing m that does this, not the leading one.
Perl has a number of quote-like operators where you can choose the delimiter to suit the data you're passing to the operator.
q(...) creates a single-quoted string
qq(...) creates a double-quoted string
qw(...) creates a list by splitting its arguments on white-space
qx(...) executes a command and returns the output
qr(...) compiles a regular expression
m(...) matches its argument as a regular expression
(There's also s(...)(...) but I've left that off the list as it has two arguments)
For some of these, you can omit the letter at the start of the operator if you choose the default delimiter.
You can omit q if you use single quote characters ('...').
You can omit qq if you use double quote characters ("...").
You can omit qx if you use backticks (`...`).
You can omit m if you use slashes (/.../).
So, to answer your original question, m/.../ and /.../ are the same, but because slashes are the default delimitor for the match operator, you can omit the m.
The pattern match syntax in Perl is as follows...
$ctr01 += s/bin/bash/gi;
This would replace bin with bash. But if there is a forward slash in the string I want to replace, how would I write it?
How can i replace "/bin/sh" to "/bin/bash", because the forward slash messes with my syntax.
You can use a different regex separator, such as #, or nearly anything you choose: (This tutorial shows some additional examples with the m operator; you can use this with s also.)
$ctr01 =~ s#/bin/sh#/bin/bash#gi;
Alternately, you can escape the slashes:
$ctr01 =~ s/\/bin\/sh/\/bin\/bash/gi;
You "escape" a forward slash with a backslash - or you change the separator (the first character after the s doesn't have to be a /, it could be anything you choose).
Since what you want to replace is at the end of a path and string, you can just use $ to anchor it for the replacement, w/o worrying about the slashes:
use strict;
use warnings;
my $ctr01 = '/bin/sh';
$ctr01 =~ s/sh$/bash/;
print $ctr01;
Output:
/bin/bash
$ctr01 += s/bin/bash/gi;
This would replace bin with bash.
No, actually it would give you a warning
Argument "/bash/bash" isn't numeric in addition (+)
And return 1 (the return value of the substitution). The operator you are using is an assignment operator +=, which is shorthand for incrementing the left hand argument by the right hand, e.g. $foo += $bar is shorthand for $foo = $foo + $bar. What you want is =~, which is the binding operator.
Also, replacing "bin" with "bash" is not what you want. You want to replace "sh" with "bash".
Overcoming the delimiters for the substitution operator is easy, because you can use whatever punctuation character you like. You will want to be sure to only replace what you want to replace, though:
$crt01 =~ s#/bin/sh#/bin/bash#g
You probably don't want the /i modifier, because the path is case sensitive.
declare a scalar variable for the search pattern and the replace pattern.
$search="/bin/sh";
$replace="/bin/bash";
if (/$search/gi) {
s/$search/$replace/gi;
}
I've to match a regular-expression, stored in a variable:
#!/bin/env perl
use warnings;
use strict;
my $expr = qr/\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)/sx;
$str = "abcd[3] xyzg[4:0]";
if ($str =~ m/$expr/) {
print "\n%%%%%%%%% $`-----$&-----$'\n";
}
else {
print "\n********* NOT MATCHED\n";
}
But I'm getting the outout in $& as
%%%%%%%%% -----abcd[3] xyzg-----[4:0]
But expecting, it shouldn't go inside the if clause.
What is intended is:
if $str = "abcd xyzg" => %%%%%%%%% -----abcd xyzg----- (CORRECT)
if $str = "abcd[2] xyzg" => %%%%%%%%% -----abcd[2] xyzg----- (CORRECT)
if $str = "abcd[2] xyzg[3] => %%%%%%%%% -----abcd[2] xyzg[3]----- (CORRECT)
if $str = "abcd[2:0] xyzg[3] => ********* NOT MATCHED (CORRECT)
if $str = "abcd[2:0] xyzg[3:0] => ********* NOT MATCHED (CORRECT)
if $str = "abcd[2] xyzg[3:0]" => ********* NOT MATCHED (CORRECT/INTENDED)
but output is %%%%%%%%% -----abcd[2] xyzg-----[3:0] (WRONG)
OR better to say this is not intended.
In this case, it should/my_expectation go to the else block.
Even I don't know, why $& take a portion of the string (abcd[2] xyzg), and $' having [3:0]?
HOW?
It should match the full, not a part like the above. If it didn't, it shouldn't go to the if clause.
Can anyone please help me to change my $expr pattern, so that I can have what is intended?
By default, Perl regexes only look for a matching substring of the given string. In order to force comparison against the entire string, you need to indicate that the regex begins at the beginning of the string and ends at the end by using ^ and $:
my $expr = qr/^\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)$/;
(Also, there's no reason to have the /x modifier, as your regex doesn't include any literal whitespace or # characters, and there's no reason for the /s modifier, as you're not using ..)
EDIT: If you don't want the regex to match against the entire string, but you want it to reject anything in which the matching portion is followed by something like "[0:0]", the simplest way would be to use lookahead:
my $expr = qr/^\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\]|(?=[^[\w])|$ ))/x;
This will match anything that takes the following form:
beginning of the string (which your example in the comments seems to imply you want)
zero or more whitespace characters
one or more word characters
optional: [, one or more digits, ]
one or more whitespace characters
one or more word characters
one of the following, in descending order of preference:
[, one or more digits, ]
an empty string followed by (but not including!) a character that is neither [ nor a word character (The exclusion of word characters is to keep the regex engine from succeeding on "a[0] bc[1:2]" by only matching "a[0] b".)
end of string (A space is needed after the $ to keep it from merging with the following ) to form the name of a special variable, and this entails the reintroduction of the /x option.)
Do you have any more unstated requirements that need to be satisfied?
The short answer is your regexp is wrong.
We can't fix it for you without you explaining what you need exactly, and the community is not going to write a regexp exactly for your purpose because that's just too localized a question that only helps you this one time.
You need to ask something more general about regexps that we can explain to you, that will help you fix your regexp, and help others fix theirs.
Here's my general answer when you're having trouble testing your regexp. Use a regexp tool, like the regex buddy one.
So I'm going to give a specific answer about what you're overlooking here:
Let's make this example smaller:
Your pattern is a(bc+d)?. It will match: abcd abccd etc. While it will not match bcd nor bzd in the case of abzd it will match as matching only a because the whole group of bc+d is optional. Similarly it will match abcbcd as a dropping the whole optional group that couldn't be matched (at the second b).
Regexps will match as much of the string as they can and return a true match when they can match something and have satisfied the entire pattern. If you make something optional, they will leave it out when they have to including it only when it's present and matches.
Here's what you tried:
qr/\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)/sx
First, s and x aren't needed modifiers here.
Second, this regex can match:
Any or no whitespace followed by
a word of at least one alpha character followed by
optionally a grouped square bracketed number with at least one digit (eg [0] or [9999]) followed by
at least one white space followed by
a word of at least one alpha character followed by
optionally a square bracketed number with at least one digit.
Clearly when you ask it to match abcd[0] xyzg[0:4] the colon ends the \d+ pattern but doesn't satisfy the \] so it backtracks the whole group, and then happily finds the group was optional. So by not matching the last optional group, your pattern has matched successfully.
What is the difference between these two operators? Specifically, what difference in $a will lead to different behavior between the two?
$a =~ /^pattern$/
$a eq 'pattern'
eq is for testing string equality, == is the same thing but for numerical equality.
The =~ operator is for applying a regular expression to a scalar.
For the gory details of every Perl operator and what they're for, see the perldoc perlop manpage.
As others have noted, ($a =~ /^pattern$/) uses the regular expression engine to evaluate whether the strings are identical, whereas ($a eq 'pattern') is the plain string equality test.
If you really only want to know whether two strings are identical, the latter is preferred for reasons of:
Readability - It is more concise, containing fewer special characters.
Maintainability - With a regex pattern, you must escape any special characters that may appear in your string, or use extra markers such as \Q and \E. With a single-quoted string, the only character you need to escape is a single quote. (You also have to escape backslashes if they are followed by another backslash or the string delimiter.)
Performance - You don't incur the overhead of firing up the regex engine just to compare a string. If this happens several million times in your program, for example, the benefit is notable.
On the other hand, the regex form is far more flexible if you need to do something other than a plain string equality test. See perldoc perlre for more on regular expressions.
EDIT: Like most everyone else before ysth, I missed the obvious functional difference between them and went straight for more abstract differences. I've clarified the question but I'll leave the answer as a (hopefully) useful reference.
eq -- Tests for string equality.
=~ -- Binds a scalar expression to a pattern match.
See here for more in-depth descriptions of all of the operators.
"pattern\n" :)
$a = "pattern\n";
print "ok 1\n" if $a =~ /^pattern$/;
print "ok 2\n" if $a eq 'pattern';
Perhaps you meant /^pattern\z/.
=~ is the binding operator. It is used to bind a value to either a pattern match (m//), a substitution (s///), or a transliteration (tr// or y//).
eq is the string equality operator; it compares two values to determine whether or not they're equal when considered as strings. There is a peer == operator that does the same thing only considering the values as numbers. (In Perl, strings and numbers are mostly interchangeable with conversions happening automatically depending on how the values are used. Because of this, when you want to compare two values you must specify the type of comparison to perform.)
In general, $var =~ m/.../ determines whether or not the value of $var matches a pattern, not whether it equals a particular value. However, in this case the pattern is anchored at both ends and contains nothing but literal characters, so it's equivalent to a string comparison. It's better to use eq here because it's clearer and faster.