http://www.perlmonks.org?node_id=140214

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

what is a regular expression to match a word containging all and only a set of characters? egs: for the set t,a,b tab should match and bat should match but not bbat or brat!

Replies are listed 'Best First'.
Re: regular xpression stuff
by Masem (Monsignor) on Jan 20, 2002 at 21:00 UTC
    In this case, you don't want a regex, at least directly. I think we've golfed this once, but in general:
    my $to_be_matched = 'tab'; my $word = 'bat'; if ( join '', sort split(//, $word) eq join '', sort split(//, $to_be_matched ) ) { # Success! } else { # Failure }

    Update - $ instead of @ on to_be_matched

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    "I can see my house from here!"
    It's not what you know, but knowing how to find it if you don't know that's important

      shouldnt
      if ( join '', sort split(//, $word) eq join '', sort split(//, $to_be_matched ) ) {
      be
      if ( join('', sort split(//, $word)) eq join('', sort split(//, $to_be +_matched)) ) {
      (extra parenthesis added )

      After adding the parenthesis , i get "Success" (i.e. "bat" = "tab" based on your example), without them the result is "Failure"
Re: regular xpression stuff
by Parham (Friar) on Jan 20, 2002 at 21:24 UTC
    this would also work
    $var = 'bat'; if ($var =~ /^[bat]{3}$/) { print "match"; } else { print "fail"; }
    since you want only those letters to exist, check from beginning to end that word for each letter, the {3} should be the number of letters in that word
      If I'm understanding the question correctly, this will not work.

      It seems that the inquiring monk wants to match each letter once and only once.
      /^[bat]{3}$/ could match 'ttt', 'bba', 'aaa', etc. If that *is* undesirable, Masem's excellent reply is probably the best way to go.
        count0++ i forgot to take that into consideration
Re: regular xpression stuff
by Lucky (Scribe) on Jan 20, 2002 at 22:01 UTC
    Looks terrific but works:
    @to_check=('bat','bbat','brat'); for (@to_check){ if (/^([bat])(?!\1)([bat])(?!\2)([bat])(?!\3)/){ # do something } }
    Just create regexp dynamically.
      if (/^([bat])(?!\1)([bat])(?!\2)([bat])(?!\3)/){</i>

      This does not entirely work, 'bab', for instance, passes the match.

      the following modified version works, but it is not too elegant, just imagine checking a 5 letter word!

      if (/^([bat])(?!\1)([bat])(?!\2|\1)([bat])(?!\3|\2|\1)/){

      Will perl for money
      JJ Knitis
      (901) 756-7693
      gt8073a@industrialmusic.com

        For any word:
        my $set='bat'; my $regexp; for (my $i=1;$i<=length($set);$i++){ my $x=join '|', map {"\\$_"} 1..$i; $regexp.="([$set])(?!$x)"; } if (/^$regexp/){ # do something }
        Terrible... :-)