3

Please help me to understand one strange problem in equality of strings. This is the code I'm talking about:

my $test=undef;
foreach my $List (@o_descrL) {
  if (!($test)) {
    $test = defined($o_noreg)
      ? $descr_d eq $List
      : $descr_d =~ /$List/i;
      printf("$descr_d = $List\t\t==> $test\n");
   }
}

Unfortunately I didn't write it but I have to understand it. $List is always "SQL Server (C4)", $descr_d is changing according to actual item in array. Part of the printed output is here:

Power = SQL Server (C4)         ==>
SQL Server (C4) = SQL Server (C4)               ==>
SNMP Service = SQL Server (C4)          ==>
Network Connections = SQL Server (C4)           ==>

As you can see, strings in the second line of the output are equal. So why isn't $test true?


EDIT: I've printed some more output and found out that when $descr_d eq $List, it equals, but not if $descr_d =~ $List. Could you please explain what is actually putting to the $test variable? I don't understand what does defined() ? : mean in here.


EDIT2: For a string "SQL Server Agent" the script works just fine, there is a problem only when (C4) is attached. Quite strange, isn't it?

Jakub Turcovsky
  • 2,096
  • 4
  • 30
  • 41

1 Answers1

11

When a string is interpolated as a regex, it isn't matched literally, but interpreted as a regex. This is useful to build complex regexes, e.g.

my @animals = qw/ cat dog goldfish /;
my $animal_re = join "|", @animals;

say "The $thing is an animal" if $thing =~ /$animal_re/i;

In the string $animal_re, the | is treated as a regex metacharacter.

Other metacharacters are e.g. (...), which is a capture group. This is present in your $List. That is, your regex is actually looking for the string SQL Server C4 and capturing the C4 when successful.

To deactivate metacharacters, you can quote them like

/\Q$metachars\E/

In your case:

$test = defined($o_noreg)
      ? $descr_d eq $List
      : $descr_d =~ /\Q$List/i;

As an aside, Perl's default false value is the empty string. Your output may be more readable if you force it to a number, e.g via $test += 0. It might also be helpful to print out the strings enclosed in quotes:

print qq("$descr_d" = "$List"\t==> $test\n);

Re: your edit

The conditional operator is common in C-like languages. It consists of three parts:

COND ? EXPR_A : EXPR_B

If the condition COND is true, the expression EXPR_A is evaluated; otherwise, EXPR_B is. In your code, the value of the expression that was evaluated is assigned to $test.

The defined builtin tests whether the value the scalar holds is undef. If that is the case, it returns a false value, or 1 otherwise. This is used for some configuration here: When $o_noreg is set to any value except undef, default string comparison will be used. If it is undef, the regex will be executed.

Re: edit 2

No it isn't strange: SQL Server (C4) contains the ( and ) metacharacters, whereas SQL Server Agent contains no metacharacters whatsoever.

darch
  • 4,200
  • 1
  • 20
  • 23
amon
  • 57,091
  • 2
  • 89
  • 149