Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Simple Regular Expression Problem 1

Status
Not open for further replies.

JJ1

Programmer
Apr 19, 2001
104
GB
Hi All,

I'm a relative newbie to Perl and am developing a script to use net::telnet::cisco for labelling a network's switch ports. The problem I have is with this code:


#$name is the new name for the switch port.
#$ports[$i][1] is the existing name of the switch port.

for my $i ( 0..$#ports ){

#If port label is already correct
[red]if ( $name =~ m/$ports[$i][1]/ig ){[/red]
print "Label already correct";
next;
}

#etc...
}


More often than not, $ports[$i][1] = "" and $name = "my_machine" or similar.

Unfortunately, the regular expression thinks that "" eq "my_machine" and so the if condition is entered when it shouldn't be.

Why is this? Could anyone point out what (stupid) mistake I've made with the regular expression?

Many thanks,

James.
 
It looks like perl is mathching because "" does exist inside all strings. Try this:
Code:
if ( $name =~ m/$ports[$i][1]/ig ){
    next unless $ports[$i][1];
    print "Label already correct";
    next;
}
Will. will@hellacool.co.uk
 
James,

Each string e.g. "my_machine" contains empty string, so your if (...) expression is true if $port[$i][1]="". Try to revert it:
Code:
if ($port[$i][1] =~ m/$name/ig) ...

Hope this helps
Grzegorz
 
Grzegorz:

Your suggestion did seem to work, but I can't understand why. Surely if all strings contain the empty string, then reversing the expression would make no difference? Please explain if you can.

Will:

Did you mean:
if ( $name =~ m/$ports[$i][1]/ig ){
if ( $ports[$i][1] ) {
print "Already Correct Label";
next;
}
}

i.e. 'next', if $ports[$i][1] actually contains a string.

Thanks anyway, it has solved my problem.

James.
 
If you are trying to make sure that the two strings are the same, you should be using string comparison instead of regular expressions. (If the reason you're using them is to get a case insensitive compare, I tend to convert strings to lower case for string comparison first.)

So:
[tt]if (lc $name eq lc $ports[$i][1])[/tt]

If you do use regular expressions the way you indicate, you're just saying "be true if the string to the left of [tt]=~[/tt] contains something matching the regular expression on the right."

That's why everything matched when the regular expression on the right was empty, and why that's not the case when the thing on the left is, instead, empty.

The problem with reversing it, though, is that you'll run into other cases where you'll get an unexpected match. Say [tt]$ports[$i][1] = "newjersey"[/tt] and [tt]$name = "new"[/tt].

If you want to use regular expressions, I would go with:
[tt]if ($name =~ m/^$ports[$i][1]$/i){[/tt]

The [tt]^[/tt] matches the start of the string, the trailing [tt]$[/tt] matches the end of the string. This means that [tt]$name[/tt] must exactly match (case insensitively) [tt]$ports[$i][1][/tt]
 
When you say:

----------------------------------------
Did you mean:
Code:
if ( $name =~ m/$ports[$i][1]/ig ){
    if ( $ports[$i][1] ) {
        print "Already Correct Label";
        next;
    }
}
----------------------------------------

this does the same as the one I suggested. This:

----------------------------------------
i.e. 'next', if $ports[$i][1] actually contains a string.
----------------------------------------

does the opposite of what I suggested.

Will. will@hellacool.co.uk
 
James,

In the regexp expression there are two main elements:
- string, that we check if it match the pattern
- pattern which we try to find within the string.

The =~ is not the comparison operator, it is the regular expression matching operator.

The syntax, more or less looks like this:
Code:
$string =~ options/$pattern/options;
and it means (more or less): does the $string match the $pattern, according to the regular expression rules ?

So if the $string is empty it cannot match $pattern, which does not represent an empty string.
But each non-empty $string, matches the empty $pattern, according to the regular expression rules (some of the rules are arbitrary established).

Grzegorz
 
I also agree with rosenk, and it really seems that in this case, comparison (eq) is better than pattern matching.

Grzegorz
 
rosenk,

Thanks for your help. I guess my problem was omitting the '^' and '$' - newbie mistake. Your other suggestion is good too i.e. lc $name eq lc $ports[$i][1]).

Thanks to all.

James.
 
Great! Thank you everyone who has helped me on this issue. I have just one more regular expression question (which I couldn't find the answer to in perlre).

I am trying to match the mac address in the following:
(The MAC address is shown in red)
@cam_table ="
Non-static Address Table:
Destination Address Address Type VLAN Destination Port
------------------- ------------ ---- --------------------
[red]0002.a553.2647[/red] Dynamic 1 FastEthernet0/22";

and I guess the following would do:

foreach my $l( @cam_table ){
if ( $l =~ m/^([a-f0-9]{4}.[a-f0-9]{4}.[a-f0-9]{4})/i ){
$mac = $1;
}
}

MAC addresses are hexadecimal and so they can only have characters a-f and 0-9.

Does that look correct or would I need a pipe (|) in the character classes i.e. [a-f|0-9] ?

 
You have it right, but you should probably put a [tt]\[/tt] before each of the "."s that you really want to match a "." character. Otherwise it would match any character and the string "aaaaZaaaaZaaaa" would match.

[tt]if ( $l =~ m/^([a-f0-9]{4}\.[a-f0-9]{4}\.[a-f0-9]{4})/i ){[/tt]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top