When solving word puzzles it is often handy to check if a string has duplicate letters in it. Here is a quick function to do that.

If you want to check for dups that are broader (letters, numbers punctuation) or narrower (eg just vowels) than just normal letters you can supply your own alphabet.

For illustration purposes the function is dropped in to a trivial program.

#!/usr/local/bin/perl my $dups = &has_dup_letters (@ARGV); if ($dups) { print "There is/are $dups dup(s).\n"; } else { print "There are no dups.\n"; } sub has_dup_letters { # Takes a word and optionally an alphabet. # Returns the number of duplications (0 for none). eg abc # Returns the number of duplications are measured as letters remov +ed to # make it unique. eg abbc == 1; abbbc == abbcc ==2; # Characters not in the alphabet are ignored regardless of # duplication. # If you do not supply an alphabet it will use a-z. If you wanted # to check different characters (vowels) or numbers or punctuation +, # just include them in your alphabet. # Case of A-Z is ignored. Trailing \n of words are chomped. my ($word, $alphabet) = @_; unless ($alphabet) { $alphabet = 'abcdefghijklmnopqrstuvwxyz' }; $alphabet_size = length $alphabet; chomp $word; # down case it $word =~ tr/A-Z/a-z/; # Remove chars not in the alphabet. $word =~ s/[^$alphabet]//g; $alphabet =~ s/[$word]//g; unless ((length($alphabet) + length($word)) == $alphabet_size) { length ($alphabet) + length ($word) - $alphabet_size; # has du +ps } else { 0; # No Dups } }

Replies are listed 'Best First'.
Re: Find duplicate chars in a string
by merlyn (Sage) on Oct 14, 2001 at 05:51 UTC
    sub has_dup_letters { local $_ = shift; tr/a-zA-Z//cd; tr/A-Z/a-z/; my %dups; scalar grep $dups{$_}++ for split //; }

    -- Randal L. Schwartz, Perl hacker


    code fix: Durnit. replace:
    scalar grep $dups{$_}++ for split //;
    with
    scalar grep $dups{$_}++, split //;
    I've been in "postfix for" mode for some reason.

      Um... that code doesn't compile, nor does it do the same thing as the original code. This is my version (it could use whatever error checking you might want on the user-supplied alphabet, though):

      sub has_dup_letters { local $_ = lc shift; my $alpha = @_ ? shift : 'a-z'; eval "tr/$alpha//cd"; my (%dups, $total); $dups{$_}++ and $total++ for split //; return $total; }

      His Royal Cheeziness

        eval "tr/$alpha//cd";
        That can be evil if $alpha contains a slash or is untrusted. To do that tr right requires some really careful thinking.

        That's why I conveniently ignored all but the basic specification. {grin}

        -- Randal L. Schwartz, Perl hacker

      ## ITYM scalar grep $dups{$_}++, split //;