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

If I want to search for a sting in Perl, but not have a bunch of code, how would I do this?

if ($string eq m/(this|or_this|or_that)/i) {

It must be an exact match, so would that work, OR would I have to do it the long way, like this:
if ($string eq "this" || $string eq "or_this" || $string eq "or_that") + {


The second way, Is much too long, as I'll have several different ones to search, more then 3, less than 10.

So, will my first way work?

Thanks,
Richard.

Replies are listed 'Best First'.
Re: matching strings...
by diotalevi (Canon) on Jan 27, 2003 at 07:44 UTC

    I usually solve this with a subroutine. I'll provide a few - one for regex matching and two for plain 'contains' or 'equals' matching.

    The whole idea here is I'm just sticking the operator into a subroutine and calling each value in turn until either the list is exhausted or something matched successfully. I understand this somewhat of the idea behind the junction operators in perl6. Anyhow, check out List::Util for more thoughts along these lines.

    sub qrany { $_ =~ $_[0] && return 1 for @_[1 .. $#_]; return } sub cany { index($_[0],$_) != -1 && return 1 for @_[1 .. $#_]; return + } sub eqany { $_ eq $_[0] && return 1 for @_[1 .. $#_]; return } # Contains tests if (cany( $string, qw[this or_this or_that]) {.... or # Equality tests if (eqany( $string, qw[this or_this or_that]) {.... or # Regex tests if (qrany( $string, qr/one regex/, qr/another regex/, qr/yet another regex/ )) { ....

    Updated Added eqany and some comments on the usage of each

    UpdatedFixed the words "three and two". Also added the second paragraph


    Seeking Green geeks in Minnesota

Re: matching strings...
by robartes (Priest) on Jan 27, 2003 at 07:31 UTC
    Hi Richard,

    Your first way will work, except that you need to use the binding operator =~ instead of the equality operator eq:

    if ($string =~ m/(this|or_this|or_that)/i)
    Also note that the m in the matching operator is not strictly necessary, as you are using the default delimiters (/). It is only necessary if you use different delimiters, e.g. m#///#, where different delimiters are used to avoid leaning toothpick syndrome.

    For more information on regular expressions perlre is your first stop.

    CU
    Robartes-

Re: matching strings...
by dempa (Friar) on Jan 27, 2003 at 07:32 UTC

    Try this:

    if ($string =~ m/^(this|or_this|or_that)$/i) { ... }

    update: Since I'm being downvoted, maybe I wasn't clear enough. I replaced eq with =~ and inserted the ^ (beginning of line) and the $ (end of line) matching operators. This to ensure that you receive an exact match for "this" or "or_this" or "or_that" (otherwise "foothisbar" would have matched).

    -- 
    dempa

      Thank you, Dempa, and everyone else too :o)

      That worked. I have what I guess is called a hash:

      @field = ( {name=> "this", size=>2, value=>"none", req=>1}, {name=> "this_one", size=>4, value=>"none2"} );

      Kind of like that one, but more fields, and obviously different.
      I use it for our registration system, however, I also am going to use the same one for a contact us form, but I don't need username, password and so forth, so I when I'm building my form with CGI.pm from that "hash", I am having it skip the fields I don't want in the form, using next if $string eq "name";

      I wanted it all to be in the same line though, instead of a bunch of needless code.

      It worked.

      Thank you!
      Richard
Re: matching strings...
by Aragorn (Curate) on Jan 27, 2003 at 08:32 UTC
    The second way, Is much too long, as I'll have several different ones to search, more then 3, less than 10.

    To make things more flexible, you can generate your regex on-the-fly using the qr operator. A simple-minded example:

    #!/usr/bin/perl -w use strict; my $words = join("|", qw(these are words that can be matched)); my $wre = qr/^($words)$/i; my $w = <STDIN>; if ($w =~ $wre) { print "I know that word\n"; }

    I don't know if it could help your program doing something like this, but it's just an idea.

    Arjen

    Update: This will only work with strings that do not contain regex metacharacters.

Re: matching strings...
by gjb (Vicar) on Jan 27, 2003 at 08:25 UTC

    Why not use a list operator in this case? grep comes to mind, but especially first that is in the List::Util module (part of the Perl 5.8 distribution if memory serves).

    use List::Util qw( first ); if (defined(first {'abc' eq $_} qw( abc def ghi ))) { print "found 'abc'\n"; }

    Hope this helps, -gjb-

    Update: Thanks to diotalevi for pointing out issues with my solution. I agree with both: I suggested first for exactly his objection to grep and I modified the original code by adding defined to resolve his objection to find.

      Both of these are poor choices. You wouldn't use grep because that's a wasteful way to program. Not only does it not stop after finding a match, it goes to all the trouble to create a copy of the matching elements in memory. The first() function is also poor because that assumes that the data itself evaluates as a 'true' value. That doesn't work when your data is things like "" and 0.


      Seeking Green geeks in Minnesota

Re: matching strings...
by Aristotle (Chancellor) on Jan 27, 2003 at 11:36 UTC
    I'm surprised noone pointed out the obvious yet:
    if(grep $string eq $_, qw(this that the_other)) { # ... }
    In scalar context, grep returns the number of matched elements, and if that's zero, the condition is false, if it's anything more then zero, it succeeds.

    Makeshifts last the longest.