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

I have a very simple problem (At least I think so), but I really can't figure it out. Maby I'm to tired, or maby just to to stupid (hope it's not the later :). What I would like to do is to use som kind of reqex to see if a given string ONLY contain characters that exist in a array of characters.

untested and not working example:
#!/usr/bin/perl my $string = "Helloa, this is the string"; my $chars = ['A'..'Z', 'a'..'z', '0'..'9']; if ($string =~ # Some sexy reqex #) { print "Okaj your alright, way to go mate."; } else { print "No way man, you'r outa here"; }

Martin A -- Just Another Perl Hooker

Replies are listed 'Best First'.
Re: Some sexy regex
by suaveant (Parson) on Apr 05, 2001 at 22:07 UTC
    $foo = join '', @{$chars}; $string =~ /^[\Q$foo\E]+$/;
    ^ and $ to make sure it matches from beginning to end, and \Q and \E to make sure it puts a \ in front of non letters chars... If it returns true, you are all good
    also... you could do
    $string =~ /[^\Q$foo\E]/;
    and fail if that matches, would probably be faster since it stops as soon as it finds a character you don't want
                    - Ant
Re: Some sexy regex
by dws (Chancellor) on Apr 05, 2001 at 22:23 UTC
    Reverse the test. Rather than making sure that the string contains only the characters that you're allowing, look instead for any that aren't in that set.
    if ( $string =~ /[^A-Za-z0-9]/ ) { print "On your bike, mate"; } else { ...
Re: Some sexy regex
by extremely (Priest) on Apr 05, 2001 at 22:22 UTC
    Well, you could do this if you don't mind tinkering with special variables:
    { # localizing $" is a good idea... local $"=""; if ($string =~ m#^[@$chars]$#) { print "OKie! $string is a subset of @$chars\n"; } else { print "Bad $string! Bad!\n"; } }

    $" sets the string that perl puts between items in an array when the array is interpolated in a doublequoted string. BTW, regexen are treated like doublequoted strings. You can stick variables in there, backwhack for special characters like \n and much more. =)

    --
    $you = new YOU;
    honk() if $you->love(perl)

Re: Some sexy regex
by runrig (Abbot) on Apr 05, 2001 at 22:13 UTC
    This may help:
    #!/usr/bin/perl -l -w use strict; my $str1 = "abc"; my $str2 = "abcde"; my @arr = qw(a b c); my $chars = join '', @arr; my $re = qr(^[\Q$chars\E]+$); print "hello1" if $str1 =~ $re; print "hello2" if $str2 =~ $re;
Re: Some sexy regex
by chromatic (Archbishop) on Apr 06, 2001 at 00:02 UTC
    Must it be an array? I've had good luck with the transliteration operator:
    my $good = "abcde"; my $bad = "zyxwv"; my $mixed = "azby"; for ($good, $bad, $mixed) { print "$_ contains invalid characters!\n" if tr/a-m//c; }
    Yes, this approach has some limitations, the most severe being that tr/// doesn't perform variable interpolation. It's still nice to know.
      tr/// not taking a regex is the most sever limitation for me. (Yeah, i know there is also s///.)
Re: Some sexy regex
by the_slycer (Chaplain) on Apr 05, 2001 at 22:08 UTC
    Something like:
    if ($string =~ /^([A-z]|[0-9])+$/){
    might work for you..
    Of course that doesn't match spaces or commas, so your string will fail :-)
Re: Some sexy regex
by larrylarru (Initiate) on Apr 06, 2001 at 01:32 UTC
    I believe that you'll find Perl's built-in grep command the most useful in this situation...
    #!/usr/bin/perl my $string = "Helloa, this is the string"; my @chars = qw(s,o,m,e,c,h,a,r,s); if ( grep $string =~ /$_/, @chars ) { print "OK"; } else { print "Oops"; }
    grep applies the expression(s) in the first argument (either a single expression followed by a comma, or a block { expr1; expr2; .. exprN; } which is not followed by a comma) to each element of the list specified in the second argument, setting $_ respectively. comparable to a foreach loop so the above is more-or-less equivalent to
    foreach (@chars) { if ($string =~ /$_/) { $anymatches++ } } if ($anymatches) { print "OK" } else { print "Oops" }
    hope this helps

    p.s. just showing off but you could do this on one line: print grep $string=~/$_/,@chars ? "OK" : "Oops";

      foreach (@chars) { if ($string=~ /$_{$anymatches++} } if($anymatches) {print "ok"} esle {print "Oops"