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

I want an operation that pulls the characters that appear in all three strings. For example, $a=1234579 $b=234789 $c=4578 in this case, $in_all=47 I can do this with an ugly set of nested if-statements. I'd like something more elegant. Can someone help? Thanks.

Replies are listed 'Best First'.
Re: Find characters in ALL strings
by FunkyMonk (Bishop) on Sep 20, 2007 at 17:44 UTC
    You could use a negated character class using all but one of your strings to remove those characters using s///:
    my @s = qw/ 1234579 234789 4578 /; my $common = pop @s; $common =~ s/[^$_]//g for @s; print $common; # 47

    update: reworded description of solution. It's still crap, though:(

      Nice! You should probably use quotemeta in case the strings contain special characters.
      my $common = pop @s; $common =~ s/[^\Q$_\E]//g for @s;

      This will die if it hits a string the regex sees as relevant but invalid (e.g, "7-4").

      I like this one better than mine. It is cleverer.
Re: Find characters in ALL strings
by ikegami (Patriarch) on Sep 20, 2007 at 18:28 UTC

    Alternative:

    my %counts; my @commons = grep { ++$counts{$_} == @s } map { my %seen; $seen{$_}++ for /./sg; keys %seen } @s;

    or

    use List::MoreUtils qw( uniq ); my %counts; my @commons = grep { ++$counts{$_} == @s } map { uniq /./sg } @s;

    Tested.

Re: Find characters in ALL strings
by kyle (Abbot) on Sep 20, 2007 at 18:03 UTC
    my @strings = qw( 1234579 234789 4578 ); my %c = map { $_ => 1 } split //, shift @strings; %c = map { $_ => 1 } grep { $c{$_} } split // for @strings; print keys %c, "\n";

    This will give you a list of characters, but it doesn't preserve order. When I ran it, I got '47', but it could just as easily have been '74'. I can't tell from your problem definition whether that's relevant or not, but I suspect it's not.

Re: Find characters in ALL strings
by n8g (Sexton) on Sep 20, 2007 at 17:46 UTC

    I would try popping a character at a time off the first string and looking for a match in the other two. Save matches and loop until there are no more characters in the first string.

    I would post my attempt at the code but I have a feeling this is homework.

Re: Find characters in ALL strings
by Roy Johnson (Monsignor) on Sep 20, 2007 at 20:28 UTC
    If there's some character you can guarantee is not in the strings (so that you can use as a separator — I chose space), you could do
    my @common = (join ' ', @s) =~ /(.)(?=(?:.* .*\1){$#s})/g;
    Not really elegant; I just thought it was a nifty one-liner.

    Caution: Contents may have been coded under pressure.
Re: Find characters in ALL strings
by Anonymous Monk on Sep 21, 2007 at 11:17 UTC
    Experts: This is NOT homework in the sense you're thinking. I am 55 years old and trying to teach myself Perl by writing a sudoku solver. Thank you for your help.
      At 55, (according to my daughter) you should be solving these BY HAND, using ONLY your greymatter & a pencil. She read where it delays the onset of Alzheimers, so for Christmas, I rec'd a 3 foot stack of Sudoku books... bless her heart. I keep pointing to my forehead & telling her "Honey, Someday, THIS will all be yours". I'd be interested in seeing your solution when it's finished. Maybe you could put it under "Cool uses for Perl"?