http://qs321.pair.com?node_id=751890

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

I want to find words containing at least 3 vowels. This is what I am trying:

#!/usr/bin/perl
@myarray=qw/......it contain words..../;
@vowels=qw/a e i o u/;
foreach(@myarray) {
$var=$_;
for ( $p=0; $p<5 ; $p++ ) {
for ( $q=0; $q<5 ; $q++ ) {
for ( $r=0; $r<5 ; $r++ ) {
if ( $var =~ /^(.*)($vowels$p)(.*)$vowels$q(.*)$vowels$r(.*)$/ )
{ push @words_having_3_vowels, $var;
}
}
}
}
}
print "@words_having_3_vowels \n";
But not getting the expected results.

Replies are listed 'Best First'.
Re: Finding vowels
by ikegami (Patriarch) on Mar 19, 2009 at 22:53 UTC

    If you wanted to use a regexp match, you could use a character class instead of your three nested loops.

    [ Code not provided as this sounds like homework ]

    By the way, it makes no sense to hardcode 5 instead of using the length of the array.

Re: Finding vowels
by linuxer (Curate) on Mar 19, 2009 at 22:10 UTC

    Please use code tags around your code...

    What about something like this:

    #! /usr/bin/perl use strict; use warnings; while ( my $line = <DATA> ) { my $count = $line =~ tr/AEIOUaeiou//; print $count, $/; } __DATA__ no ah, two... ave ave caesar
    Please read additionally at perldoc -q count

    Updates

    1. expanded code to show a complete working example
    2. $code =~ s/cnt/count/g
Re: Finding vowels
by ww (Archbishop) on Mar 19, 2009 at 23:29 UTC
    If you're seeking words which contain three different vowels (a possibility which is neither ruled-in nor ruled-out by your initial post), this is one of many ways to do so:
    #!/usr/bin/perl use strict; use warnings; # cf pl_test/751890.pl my @myarray=qw/two three threee fouuuuur five septigesimal sodium hexa +flouride/; my @vowels=qw/a e i o u/; my @words_having_3_vowels; for my $var(@myarray) { my $seen; for my $vowel(@vowels) { if ($var =~ m/$vowel/) { $seen++; if ($seen == 3) { push @words_having_3_vowels, $var; next; } } } } for my $words(@words_having_3_vowels) { print "$words \n"; } =head execution output: pl_test/751890_a.pl septigesimal sodium hexaflouride =cut

    Now, echoing responses above, please read about <code>...</code> (or <c>...</c> tags in Writeup Formatting Tips or Markup in the Monastery so that your code is readable (what you did is, but more complex code, or that using characters like [ would NOT be readable without code tags.

    And read also How do I post a question effectively? because "But not getting the expected results." is not a description of the problem which clarifies your problem. Also, as noted above, your description of what you're trying to achieve is ambiguous./p>

    Finally, the original code, cleaned up to use strict; and use warnings;; with variables declared (albeit, not constrained as to scope with appropriate indentation (well, one legible version of 'appropriate' indentation, of which there are many);

    #!/usr/bin/perl use strict; use warnings; my @myarray=qw/two three threee fouuuuur five septigesimal/; my @vowels=qw/a e i o u/; my @words_having_3_vowels; foreach(@myarray) { my $var=$_; for ( my $p=0; $p<5 ; $p++ ) { for ( my $q=0; $q<5 ; $q++ ) { for ( my $r=0; $r<5 ; $r++ ) { if ( $var =~ /^(.*)($vowels[$p])(.*)$vowels[$q](.*)$vo +wels[$r](.*)$/ ) { push @words_having_3_vowels, $var; } } } } } for my $result(@words_having_3_vowels) { print "|$result|\n"; } =head execution output: |threee| |fouuuuur| |fouuuuur| |septigesimal| |septigesimal| |septigesimal| |septigesimal| |septigesimal| |septigesimal| |septigesimal| |septigesimal| =cut

    This is unnecessarily hard on you and the future reader and could be avoided by <insert> either of</insert> the technique ikegami cites; it's also far more work to type (and track) than linuxer's solution. Note, however, that his output is a per-word vowel count; not the words with 3 or more vowels, and also that lines 20-22 in my "cleaned up" version change your print command (line 16 by my count) to a print-in-a-loop that prints a word (wrong: each time its vowel-count exceeds two) (correction: one or more times for reasons I'm too lazy to explore and elucidate).

    Update Inserted the italicized clarification re ikegami's suggestions.
    update 2 Original statement re output, now stricken, is incorrect.

Re: Finding vowels
by bichonfrise74 (Vicar) on Mar 20, 2009 at 01:25 UTC
    How about this?
    #!/usr/bin/perl use strict; my @arrays = qw( chatterbox test abode); my @vowels = qw( a e i o u ); foreach my $i (@arrays) { my $count = 0; for (my $j = 0; $j <= (length $i) - 1 ; $j++) { my $letter = substr($i, $j, 1 ); $count++ if ( grep /\b$letter\b/, @vowels ); } print "$i has at least 3 or more vowels.\n" if ( $count >= 3 ); }

      Hi, though I still prefer the tr/// solution, I think, a rewrite of your code could be helpful ;o)

      So, how about this (based upon your solution)?

      #! /usr/bin/perl use strict; use warnings; my @array = qw( chatterbox test abode ); my @vowels = qw( a e i o u ); # check each word in @array; so why using $i instead of $word? WORD: for my $word ( @array ) { my $count = 0; # split $word into characters CHARACTER: for my $character ( split //, $word ) { # I see no need for regex if checking each character against each +vowel # check if character is equal a vowel $count++ if grep { $_ eq $character } @vowels; # could be inserted to make it (maybe?; depends on the words which + are checked) faster #last CHARACTER if $count >= 3; } print "$word has at least 3 or more vowels.\n" if $count >= 3; }
Re: Finding vowels
by Marshall (Canon) on Mar 20, 2009 at 05:33 UTC
    For the problem as stated, this is a "one line'er". The idea of tr is a good one as others have said. You don't need a foreach loop as grep is designed to filter lists. Here the number of substitutions are used in a scalar context within the grep. No changes are made to the input @array list. But you could just use @array instead of @vowelsGT2 and @array would automatically shrink.
    #!/usr/bin/perl -w use strict; my @array = qw( chatterbox teste abode fooooo foo); my @vowelsGT2 = grep{ tr/aeiouAEIOU// >2}@array; print "Words with >2 vowels: @vowelsGT2\n"; __END__ prints: Words with >2 vowels: chatterbox abode fooooo
Re: Finding vowels
by Utilitarian (Vicar) on Mar 20, 2009 at 10:29 UTC
    From a quick one liner test the following works:
    print $word if $word=~ m/([aeiou].*){3}/i;
      Than you friend.it works!
Re: Finding vowels
by tchrist (Pilgrim) on Jun 13, 2011 at 04:44 UTC
    I believe that this will do the trick. Examples of the output includes:
    brisé                      :  2 vowels total,  2 distinct
    onomatopoetically          :  9 vowels total,  5 distinct
    elaeocarpaceous            :  9 vowels total,  4 distinct
    unpopulous                 :  5 vowels total,  2 distinct
    palaeometeorology          : 10 vowels total,  4 distinct
    thyroparathyroidectomy     : 10 vowels total,  5 distinct
    ombú                       :  2 vowels total,  2 distinct
    edaciously                 :  6 vowels total,  6 distinct
    unilateralization          :  9 vowels total,  5 distinct
    amyelencephalous           :  8 vowels total,  5 distinct
    tautegory                  :  5 vowels total,  5 distinct
    schmierkäse                :  4 vowels total,  3 distinct
    diselenide                 :  5 vowels total,  2 distinct
    pseudopelletierine         :  9 vowels total,  4 distinct
    Coryphaenoididae           :  9 vowels total,  5 distinct
    brisé                      :  2 vowels total,  2 distinct
    Mimbreño                   :  3 vowels total,  3 distinct
    paleoanthropological       :  9 vowels total,  4 distinct
    L’eau-de-Sᵗᵉ-Thérèse       :  8 vowels total,  3 distinct
    Henry_Ⅷᵗʰ                  :  5 vowels total,  3 distinct
    LᵉGuin                     :  3 vowels total,  3 distinct
    MᵃᶜKenzie                  :  4 vowels total,  3 distinct
    arrière-guard              :  6 vowels total,  4 distinct
    yagé                       :  3 vowels total,  3 distinct
    prostatovesiculectomy      :  9 vowels total,  6 distinct
    microlepidopterous         :  8 vowels total,  4 distinct
    damassé                    :  3 vowels total,  2 distinct
    glycolytically             :  6 vowels total,  4 distinct
    Archaeopterygiformes       :  9 vowels total,  5 distinct
    norteño                    :  3 vowels total,  2 distinct
    duodenopancreatectomy      : 10 vowels total,  5 distinct
    hyperoödon                 :  5 vowels total,  3 distinct
    botoné                     :  3 vowels total,  2 distinct
    tête                       :  2 vowels total,  1 distinct
    Cwnic                      :  1 vowels total,  1 distinct
    Cynddelw                   :  2 vowels total,  2 distinct
    Gwgan                      :  1 vowels total,  1 distinct
    Wræððu                     :  2 vowels total,  2 distinct
    
    As you see, there’s a slight problem with some Welsh surnames. Oh well.

    Here below is the program.

    And here is the datafile attached to <DATA>:

    That should do it. I trust you’ll find the test test an interesting challenge.

    --tom