1

Let's say I have an array of strings, e.g. @matches = ("cat", "zebra", "apple"), and I want to open a file and try to match these strings in the simplest way possible.

while (<MYFILE>)
{
    chomp;

    if (..some match condition...)
    {
        ..stuff..
    }
}

I could just use a foreach on each line to try to match, but I know there's got to be a concise way in Perl to say "if string X matches any of the patterns in array Y." I just can't seem to find this anywhere.

EDIT:

To clarify, here's the highly inefficient code:

while (<MYFILE>)
{
    chomp;

    foreach $m (@matches)
    { 
        if (~ /$m/)
        {
            ..stuff..
        }
    }
}

I know there's some shorthand method of doing this.

1
  • 2
    What do you mean with “matches”? (a) “is equal to”, (b) “contains as substring”, or (c) “matches when used as regex”? Are you willing to use non-core modules? This makes a fine use-case for the any-junction Commented Jun 5, 2013 at 22:30

3 Answers 3

2

How about using join to make an impromptu regex?

my @matches = ("cat", "zebra", "apple");
my $rx = join "|", @matches;

while (<$fh>) {
    if ($_ =~ /$rx/) {
         # stuff
    }
}
Sign up to request clarification or add additional context in comments.

7 Comments

It's fine but, first, I think it would be more efficient to compile the regex only once, either with qr or adding the o flag. And second, there is to pay attention to the ordering of the words in the alternation, because cat|category could be dangerous.
@Birei You foresee some trouble with strings where cat and category will conflict?
I thought that the OP wanted to know also what matched and not only if it exists a match. No problem, forget it.
@Birei Then you could do my @words = /($rx)/g, and order will not matter.
@Birei Oh, right. Yes, I suppose that would be the better way. Although the proper way perhaps would be to not allow cat to partially match category, using for example word boundary.
|
0

You seem to want to use the entries of @matches as regexes. Then, you can join them to a larger regex:

my $rx = join '|', @matches;

while (<>) {
  do stuff if $_ =~ $rx;
}

If you want to match the literal contents of the entries of @matches, so that @matches = ("foo+") matches the line foo+ and not fooo as above solution would do, you can construct the regex like

my $rx = join '|', map quotemeta, @matches;

Comments

0
my @matches = qw( cat zebra apple );

{   local $" = '|';

    while (<>) {
        chomp;
        if (/@matches/) { ... }
    }
}

But be careful. Read the doc:

perldoc perlvar | grep "\$LIST_SEPARATOR" -A 12

:)

Comments

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.