debiandude has asked for the wisdom of the Perl Monks concerning the following question:

I want to create a regex from an array I get back from my SQL server.

For instance lets say from my SQL server I get the resutls and I put them in the array.

@results = ("1234", "ABCD", "HIGL", "TOOA", "COOLIE");

Later on I am parsing a file and I only want to parse the entries that have a name in my results array.

The regex I want would look like this:

if ($name =~ m/1234|ABCD|HIGL|TOOA|COOLIE/) { do_stuff }

So how could I transform my array into a regex? And help appreciated. Thanks.

Replies are listed 'Best First'.
Re: Creating regex from arrays
by artist (Parson) on Jul 29, 2003 at 15:37 UTC
    $regex = join '|' => map { "\($_\)" } @results; if($_ =~ qr/$regex/){ print "$_" };

    artist

      Thanks. That worked great!
Re: Creating regex from arrays
by Zaxo (Archbishop) on Jul 29, 2003 at 15:37 UTC

    Something like this works,

    my $re; { local $" = '|'; $re = qr/@results/; }
    The $" variable is interpolated between array elements in stringification.

    After Compline,
    Zaxo

      I can see that you probably posted this as a TIMTOWTDI alternative to the half-million other posts using join. I would have never thought to do it that way. I wonder: does your method have an advantage over join, or is it just as good?


      Once it's Turing complete, everything else is just syntactic sugar.

        You're right, timtowtdi sitting on my shoulder. I do like that construction, though. IMO, it's more concise and less visually noisy. True, it depends on a trick from the second tier of quote operator details, but I think the sparse notation and localization of $" pretty well telegraph what the trick is.

        I don't know if there is any performance benefit, other than what's obtained from constructing a compiled regex with qr//. That could as well be done with join. I've never benchmarked this.

        A minor refinement of the code, to assign $re where it is declared:

        my $re = do { local $" = '|'; qr/@array/; };
        or, if metacharacters may be a problem,
        my $re = do { local $" = '|'; qr/@{[map {quotemeta} @array]}/; };

        After Compline,
        Zaxo

      I thought $" was one of the bad vars tht slows down all regex in your app once used?

      -Waswas

        Not that I know of. Are you thinking of $' ?

        $" is defined with a default value of ' ' in stock perl. It is the mechanism which puts spaces between elements in print "@foo";

        After Compline,
        Zaxo

Re: Creating regex from arrays
by broquaint (Abbot) on Jul 29, 2003 at 15:47 UTC
    Further to the answers above there's presuf from the Regex::PreSuf module which is tailored specifically to solving this problem e.g
    use Regex::PreSuf; print presuf("1234", "ABCD", "HIGL", "TOOA", "COOLIE"); __output__ (?:1234|ABCD|COOLIE|HIGL|TOOA)
    It also rather niftily 'optimizes' (or 'compresses', depending on your view) the regular expression for overlapping words. See. the Regex::PreSuf docs for more info.
    HTH

    _________
    broquaint

Re: Creating regex from arrays
by liz (Monsignor) on Jul 29, 2003 at 15:49 UTC
    Other monks have answered this.

    I see only one caveat: if the character "I" can occur in your original array, you will have to escape that. Something like:

    $tomatch = join( '|',map {s#|#\\|#s; $_} @results );
    And yes, I prefer # over / for regexes to avoid the falling toothpick syndrome.

    Liz

      The fix to that problem is quotemeta, not selectively escaping pipes

      $tomatch = join "|", map quotemeta, @results;
      map {s#|#\\|#s; $_} @results

      I hope you don't have any other uses for @results as you've modified it in-place.

      Perl doesn't have a great idiom for this. This type of mistake and several others are so common that I really think Perl should have a 'filter' keyword.

      And thanks(++) for bringing up the important point about escaping regular expression metacharacters and prompting diotalevi's reply (which is what I'd use).

                      - tye
        Good point. Apart from using quotemeta, it would have been better to do:
        $tomatch = join '|', map {local $_ = $_; s#\|#\\|#s; $_} @results;
        When actually testing this, I found that my initial solution was flawed in another way: the initial pipe needs to be escaped as well! Does any monk have an idea why that is necessary?

        Liz
Re: Creating regex from arrays
by Kageneko (Scribe) on Jul 29, 2003 at 15:40 UTC
    Hmm, you could do something like this:
    my $results = join "|", @results; my $results_re = qr/$results/; ... if ( $name =~ /$results_re/ ) { ... }
    Undoubtedly, there is an easier way to do it, but that's what springs to mind. Using qr// allows you to compile the regex only once if you re-use the same results (and regex) over and over.