2

I want to check if string $name ends with any of the elements from $end array_ref

my $end=['.a[bc', '.de[f', '.xy]z'];
my $name="test.a[bc";

# But this is not working:
if(grep{$name=~m/\Q.+$_$/} @{$end}) { print "Yes\n"; } else {print "No\n"; } # prints "No"

4 Answers 4

4

The problem is that \Q escapes (and thus matches literally) .+ and $ (in addition to the contents of $_).

Fix:

grep { $name =~ /\Q$_\E\z/ } @{$end}
  • You don't need the .+ part at all.
  • \E limits the escaping to just $_.
  • \z anchors the match to the end of the string ($ would also allow a \n before the end of the string).
Sign up to request clarification or add additional context in comments.

1 Comment

Worked like charm. Thanks!
2

Allow me to offer an alternative solution without using regex. Since the problem is is to compare a string with a sub-string, substr() function can be used:

my $end = ['.a[bc', '.de[f', '.xy]z'];
my $name= "test.a[bc" ;
my $found = grep { (substr($name, length($name) - length($_)) eq $_) } @$end;
print $found ? "Yes\n": "No\n";

This is assuming length($name) >= length($_). In fact, the behaviour of substr can also allow us to simply pass a negative offset (2nd parameter):

my $found = grep { (substr($name, -length($_)) eq $_) } @$end;

One thing to note here is that substr() generally produce no errors and warnings and still do something -- since it takes both positive and negative offset values. (Check perldoc of substr (command: perldoc -f substr) for more details).

You can avoid those "surprises" by adding a pre-condiditon to guard this seemingly trivial assumption:

my $found = grep {
    (length($name) > length($_)) &&
    (substr($name, -length($_)) eq $_)
} @$end;

This does makes sense: if the content in $_ is longer than $name, by definition it cannot be the suffix of $name anyway.

1 Comment

Thanks for this non-regex solution. Brilliant!
0
my $end=['.a[bc', '.de[f', '.xy]z'];
my $name="test.a[bc";
my %end;
@end{@$end}=();
my $found = exists $end{($name=~/.*(\..*)/)[0]};

Comments

0

In order to use grep() , you need to convert the $end variable to an array by using split(). Note that grep(/pattern/,@array) searches for /pattern/ in each element of @array. Since you are searching for last four characters in your pattern , we need to separate it first.

my $end="'.a[bc', '.de[f', '.xy]z'";
my @array = split(',',$end);
my $name="test.a[bc";
my $name_end = substr($name,-5);

if( grep( m/\Q$name_end/ , @array ) ) {
    print "Yes\n";
}
else {
    print "No\n";
} # prints "No";

An alternative would be to to search in the $end for each array element by looping. The above solution works however. Let me know your feedback.

2 Comments

$end is not a string. It's an array reference.
Thanks!. I misinterpreted it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.