Count how many vowels and consonants occur in a string

From Rosetta Code
Count how many vowels and consonants occur in a string is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Task
Count how many vowels and consonants occur in a string


Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences




11l

Translation of: Python
F isvowel(c)
   ‘ true if c is an English vowel (ignore y) ’
   R c C (‘a’, ‘e’, ‘i’, ‘o’, ‘u’, ‘A’, ‘E’, ‘I’, ‘O’, ‘U’)

F isletter(c)
   ‘ true if in English standard alphabet ’
   R c C (‘a’..‘z’, ‘A’..‘Z’)

F isconsonant(c)
   ‘ true if an English consonant ’
   R !isvowel(c) & isletter(c)

F vccounts(s)
   ‘ case insensitive vowel counts, total and unique ’
   V a = Array(s.lowercase())
   V au = Set(a)
   R (sum( a.map(c -> Int(isvowel(c)))), sum( a.map(c -> Int(isconsonant(c)))),
      sum(au.map(c -> Int(isvowel(c)))), sum(au.map(c -> Int(isconsonant(c)))))

V s = ‘Now is the time for all good men to come to the aid of their country.’
V (vcnt, ccnt, vu, cu) = vccounts(s)
print(‘String: ’s"\n    Vowels: "vcnt‘ (distinct ’vu")\n    Consonants: "ccnt‘ (distinct ’cu‘)’)
Output:
String: Now is the time for all good men to come to the aid of their country.
    Vowels: 22 (distinct 5)
    Consonants: 31 (distinct 13)

Action!

PROC CountVovelsConsonants(CHAR ARRAY s BYTE POINTER vov,con)
  BYTE i
  CHAR c

  vov^=0 con^=0
  FOR i=1 TO s(0)
  DO
    c=s(i)
    IF c>='A AND c<='Z THEN
      c==+'a-'A
    FI
    IF c>='a AND c<='z THEN
      IF c='a OR c='e OR c='i OR c='o OR c='u THEN
        vov^==+1
      ELSE
        con^==+1
      FI
    FI
  OD
RETURN

PROC Test(CHAR ARRAY s)
  BYTE vov,con

  PrintE("Input string:")
  PrintE(s)
  CountVovelsConsonants(s,@vov,@con)
  PrintF("Vovel count=%I, consonant count=%I%E%E",vov,con)
RETURN

PROC Main()
  Test("Now is the time for all good men to come to the aid of their country.")
  Test("Forever Action! programming language")
RETURN
Output:

Screenshot from Atari 8-bit computer

Input string:
Now is the time for all good men to come to the aid of their country.
Vovel count=22, consonant count=31

Input string:
Forever Action! programming language
Vovel count=13, consonant count=19

Ada

This solution uses Ada 2012 aspect clauses to define discontinuous subtypes

--
-- count vowels and consonants in a string
--
with Ada.Text_IO; use Ada.Text_IO;

procedure count_vowels_and_consonants is
   subtype letter is Character with
        Static_Predicate => letter in 'A' .. 'Z' | 'a' .. 'z';
   subtype Vowel is Character with
        Static_Predicate => Vowel in 'A' | 'E' | 'I' | 'O' | 'U' | 'a' | 'e' |
            'i' | 'o' | 'u';
   subtype consonant is Character with
        Dynamic_Predicate => consonant in letter
        and then consonant not in Vowel;

   Input           : String (1 .. 1_024);
   length          : Natural;
   consonant_count : Natural := 0;
   vowel_count     : Natural := 0;
begin
   Put ("Enter a string: ");
   Get_Line (Item => Input, Last => length);
   -- count consonants
   for char of Input (1 .. length) loop
      if char in consonant then
         consonant_count := consonant_count + 1;
      elsif char in Vowel then
         vowel_count := vowel_count + 1;
      end if;
   end loop;
   Put_Line ('"' & Input (1 .. length) & '"');
   Put_Line
     ("contains" & vowel_count'Image & " vowels and" & consonant_count'Image &
      " consonants.");
end count_vowels_and_consonants;
Output:
Enter a string: If not now then when? If not us then who?
"If not now then when? If not us then who?"
contains 10 vowels and 20 consonants.

ALGOL 68

Showing total and distinct vowel/consonant counts, as in the Go, Wren etc. samples.

BEGIN # count the vowels and consonants in a string                         #
    # returns the 0-based index of the upper case letter c in the alphabet  #
    # or -1 if c is not a letter                                            #
    OP   L = ( CHAR c )INT:
         IF c >= "A" AND c <= "Z" THEN ABS c - ABS "A" ELIF c >= "a" AND c <= "z" THEN ABS c - ABS "a" ELSE -1 FI;
    # prints the counts of vowels and consonants in s                       #
    PROC print vc counts = ( STRING s )VOID:
         BEGIN
            [ 0 : 26 ]BOOL used;  FOR i FROM LWB used  TO UPB used  DO used[  i ] := FALSE OD;
            [ 0 : 26 ]BOOL vowel; FOR i FROM LWB vowel TO UPB vowel DO vowel[ i ] := FALSE OD;
            vowel[ L "A" ] := vowel[ L "E" ] := vowel[ L "I" ] := vowel[ L "O" ] := vowel[ L "U" ] := TRUE;
            INT v total := 0, c total := 0, v count := 0, c count := 0;
            FOR i FROM LWB s TO UPB s DO
                IF   INT c index = L s[ i ];
                     c index >= LWB used
                THEN
                    IF vowel[ c index ] THEN v total ELSE c total FI +:= 1;
                    IF NOT used[ c index ] THEN
                        IF vowel[ c index ] THEN v count ELSE c count FI +:= 1;
                        used[ c index ] := TRUE
                    FI
                FI
            OD;
            print( ( """", s, """ contains", newline ) );
            print( ( "    ", whole( v count, 0 ), " vowels and ", whole( c count, 0 ), " consonants (distinct)", newline ) );
            print( ( "    ", whole( v total, 0 ), " vowels and ", whole( c total, 0 ), " consonants (total)",    newline ) )
         END; # print vc counts #
    # test cases                                                            #
    print vc counts( "Now is the time for all good men to come to the aid of their country" );
    print vc counts( "Help avoid turns" )
END
Output:
"Now is the time for all good men to come to the aid of their country" contains
    5 vowels and 13 consonants (distinct)
    22 vowels and 31 consonants (total)
"Help avoid turns" contains
    5 vowels and 9 consonants (distinct)
    5 vowels and 9 consonants (total)

Applesoft BASIC

 100  DIM V(255),C(255)
 110  FOR I = 0 TO 3
 120      FOR V = 1 TO 5
 130          V( ASC ( MID$ ("AEIOU",V,1)) +  VAL ( MID$ ("000032128160",I * 3 + 1,3))) = 1
 140  NEXT V,I
 150  FOR I = 0 TO 3
 160      FOR C = 1 TO 26
 170      C( VAL ( MID$ ("064096192224",I * 3 + 1,3)) + C) =  NOT V(64 + C)
 180  NEXT C,I
 190  DEF  FN L(C) = C(C) OR V(C)
 200 S$ = "This is 1 string" +  CHR$ (13)
 210  GOSUB 290
 220 S$ = "This is a second string" +  CHR$ (13)
 230  GOSUB 290
 240  PRINT "a: "V( ASC ("a"))
 250  PRINT "b: "V( ASC ("b"))
 260  PRINT "Z: "C( ASC ("Z"))
 270  PRINT "1: " FN L( ASC ("1"))
 280  END 
 290  GOSUB 340"VOWELS"
 300  PRINT N", ";
 310  GOSUB 410"CONSONANTS"
 320  PRINT N", "L", "S$
 330  RETURN 
 340 N = 0
 350 L =  LEN (S$)
 360  IF  NOT L THEN  RETURN 
 370  FOR I = 1 TO L
 380      N = N + V( ASC ( MID$ (S$,I,1)))
 390  NEXT I
 400  RETURN 
 410 N = 0
 420 L =  LEN (S$)
 430  IF  NOT L THEN  RETURN 
 440  FOR I = 1 TO L
 450       N = N + C( ASC ( MID$ (S$,I,1)))
 460  NEXT I
 470  RETURN

Arturo

vRe: {/[aeiou]/}
cRe: {/[bcdfghjklmnpqrstvwxyz]/}

str: lower "Now is the time for all good men to come to the aid of their country."

vowels: match str vRe
consonants: match str cRe

print ["Found" size vowels "vowels -" size unique vowels "unique"]
print ["Found" size consonants "consonants -" size unique consonants "unique"]
Output:
Found 22 vowels - 5 unique 
Found 31 consonants - 13 unique

AutoHotkey

str := "Now is the time for all good men to come to the aid of their country."
oV:= [], oC := [], v := c := o := 0
for i, ch in StrSplit(str)
    if (ch ~= "i)[AEIOU]")
        v++, oV[ch] := (oV[ch]?oV[ch]:0) + 1
    else if (ch ~= "i)[A-Z]")
        c++, oC[ch] := (oC[ch]?oC[ch]:0) + 1
    else 
        o++

Vowels := "{"
for ch, count in oV
    Vowels .= """" ch """:" count ", "
Vowels := Trim(Vowels , ", ") "}"
Consonants := "{"
for ch, count in oC
    Consonants .= """" ch """:" count ", "
Consonants := Trim(Consonants , ", ") "}"

MsgBox % result := str "`n`n" v+c+o " characters, " v " vowels, " c " consonants and " o " other"
        . "`n" Vowels "`n" Consonants
Output:
Now is the time for all good men to come to the aid of their country.
69 characters, 22 vowels, 31 consonants and 16 other
{"a":2, "e":6, "i":4, "o":9, "u":1}
{"c":2, "d":2, "f":2, "g":1, "h":3, "l":2, "m":3, "N":3, "r":3, "s":1, "t":7, "w":1, "y":1}

AWK

# syntax: GAWK -f COUNT_HOW_MANY_VOWELS_AND_CONSONANTS_OCCUR_IN_A_STRING.AWK
BEGIN {
    str = "Now is the time for all good men to come to the aid of their country."
    printf("%s\n",str)
    str = toupper(str)
    for (i=1; i<=length(str); i++) {
      if (substr(str,i,1) ~ /[AEIOU]/) {
        count_vowels++
      }
      else if (substr(str,i,1) ~ /[BCDFGHJKLMNPQRSTVWXYZ]/) {
        count_consonants++
      }
      else {
        count_other++
      }
    }
    printf("%d characters, %d vowels, %d consonants, %d other\n",length(str),count_vowels,count_consonants,count_other)
    exit(0)
}
Output:
Now is the time for all good men to come to the aid of their country.
69 characters, 22 vowels, 31 consonants, 16 other

BCPL

get "libhdr"

let ucase(c) =
    'a' <= c <= 'z' -> c - 32,
    c

let letter(c) = 'A' <= ucase(c) <= 'Z'

let vowel(c) =
    ucase(c) = 'A' | 
    ucase(c) = 'E' | 
    ucase(c) = 'I' | 
    ucase(c) = 'O' | 
    ucase(c) = 'U'

let consonant(c) = letter(c) & ~vowel(c)

let count(p, s) = valof
$(  let total = 0
    for i = 1 to s%0
        if p(s%i) then total := total + 1
    resultis total
$)

let example(s) be
$(  let v = count(vowel,s)
    let c = count(consonant,s)
    writef("'%S': %N vowels, %N consonants.*N", s, v, c)
$)

let start() be 
    example("If not now, then when? If not us, then who?")
Output:
'If not now, then when? If not us, then who?': 10 vowels, 20 consonants.

C

/*

https://rosettacode.org/wiki/Count_how_many_vowels_and_consonants_occur_in_a_string

*/

#include <stdio.h>

char vowels[] = {'a','e','i','o','u','\n'};

int len(char * str) {
	int i = 0;
	while (str[i] != '\n') i++;
	return i;
}

int  isvowel(char c){
	int b = 0;
	int v = len(vowels);
	for(int i = 0; i < v;i++) {
		if(c == vowels[i]) {
			b = 1;
			break; 
		}
	}
	return b;
}

int isletter(char c){
	return ((c >= 'a') && (c <= 'z') || (c >= 'A') && (c <= 'Z'));
}

int isconsonant(char c){
	return isletter(c) && !isvowel(c);
}

int cVowels(char * str) {
	int i = 0;
	int count = 0;
	while (str[i] != '\n') {
		if (isvowel(str[i])) {
			count++;;
		}
		i++;
	}
	return count;
}

int cConsonants(char * str ) {
	int i = 0;
	int count = 0;
	while (str[i] != '\n') {
		if (isconsonant(str[i])) {
			count++;
		}
		i++;
	}
	return count;
}

int main() {

	char buff[] = "This is 1 string\n";
	printf("%4d, %4d, %4d, %s\n", cVowels(buff), cConsonants(buff), len(buff), buff);

	char buff2[] = "This is a second string\n";
	printf("%4d, %4d, %4d, %s\n", cVowels(buff2), cConsonants(buff2), len(buff2),  buff2);


	printf("a: %d\n", isvowel('a'));
	printf("b: %d\n", isvowel('b'));
	printf("Z: %d\n", isconsonant('Z'));
	printf("1: %d\n", isletter('1'));
}
Output:
   3,    9,   16, This is 1 string

   6,   13,   23, This is a second string

a: 1
b: 0
Z: 1
1: 0

CLU

ucase = proc (c: char) returns (char)
    if c>='a' & c<='z' then return(char$i2c(char$c2i(c)-32))
    else return(c)
    end
end ucase

letter = proc (c: char) returns (bool)
    c := ucase(c)
    return(c >= 'A' & c <= 'Z')
end letter

vowel = proc (c: char) returns (bool)
    return(string$indexc(ucase(c), "AEIOU") ~= 0)
end vowel

consonant = proc (c: char) returns (bool)
    return(letter(c) & ~vowel(c))
end consonant

vowels_and_consonants = proc (s: string) returns (int,int)
    vs: int := 0
    cs: int := 0
    for c: char in string$chars(s) do
        if vowel(c) then vs := vs+1
        elseif consonant(c) then cs := cs+1
        end
    end
    return(vs,cs)
end vowels_and_consonants

example = proc (s: string)
    po: stream := stream$primary_output()
    v, c: int := vowels_and_consonants(s)
    stream$putl(po, "\"" || s || "\": " || int$unparse(v)
                    || " vowels, " || int$unparse(c)
                    || " consonants.")
end example

start_up = proc ()
    example("If not now, then when? If not us, then who?")
end start_up
Output:
"If not now, then when? If not us, then who?": 10 vowels, 20 consonants.

COBOL

       IDENTIFICATION DIVISION.
       PROGRAM-ID. VOWELS-AND-CONSONANTS.
       
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 CONSTANTS.
          03 LETTERS-DAT.
             05 FILLER      PIC X(5) VALUE "AEIOU".
             05 FILLER      PIC X(5) VALUE "aeiou".
             05 FILLER      PIC X(21) VALUE "BCDFGHJKLMNPQRSTVWXYZ".
             05 FILLER      PIC X(21) VALUE "bcdfghjklmnpqrstvwxyz".
          03 LETTERS        REDEFINES LETTERS-DAT.
             05 VOWELS      PIC X OCCURS 10 TIMES INDEXED BY V.
             05 CONSONANTS  PIC X OCCURS 42 TIMES INDEXED BY C.
      
       01 VARIABLES.
          03 IN-STR         PIC X(80).
          03 N-VOWELS       PIC 99.
          03 N-CONSONANTS   PIC 99.
      
       01 REPORT.
          03 R-VOWELS       PIC Z9.
          03 FILLER         PIC X(9) VALUE " vowels, ".
          03 R-CONSONANTS   PIC Z9.
          03 FILLER         PIC X(12) VALUE " consonants.".
         
       PROCEDURE DIVISION.
       BEGIN.
           MOVE "If not now, then when? If not us, then who?"
           TO IN-STR.
           PERFORM COUNT-AND-SHOW.
           STOP RUN.
          
       COUNT-AND-SHOW.
           DISPLAY IN-STR.
           PERFORM COUNT-VOWELS-AND-CONSONANTS.
           MOVE N-VOWELS TO R-VOWELS.
           MOVE N-CONSONANTS TO R-CONSONANTS.
           DISPLAY REPORT.
       
       COUNT-VOWELS-AND-CONSONANTS.
           MOVE ZERO TO N-VOWELS, N-CONSONANTS.
           SET V TO 1.
           PERFORM COUNT-VOWEL 10 TIMES.
           SET C TO 1.
           PERFORM COUNT-CONSONANT 42 TIMES.
        
       COUNT-VOWEL.
           INSPECT IN-STR TALLYING N-VOWELS FOR ALL VOWELS(V).
           SET V UP BY 1.
       
       COUNT-CONSONANT.
           INSPECT IN-STR TALLYING N-CONSONANTS FOR ALL CONSONANTS(C).
           SET C UP BY 1.
Output:
If not now, then when? If not us, then who?
10 vowels, 20 consonants.

Common Lisp

(defun vowel-p (c &optional (vowels "aeiou"))
   (and (characterp c) (characterp (find c vowels :test #'char-equal))))

(defun count-vowels (s)
   (and (stringp s) (count-if #'vowel-p s)))

(defun count-consonants (s)
   (and (stringp s) (- (count-if #'alpha-char-p s) (count-vowels s))))

Cowgol

include "cowgol.coh";

sub vowels_consonants(s: [uint8]): (vowels: intptr, consonants: intptr) is
    vowels := 0;
    consonants := 0;
    
    while [s] != 0 loop
        var ch := [s] | 32;
        if ch >= 'a' and ch <= 'z' then
            if ch == 'a' or ch == 'e' or ch == 'i'
            or ch == 'o' or ch == 'u' then
                vowels := vowels + 1;
            else
                consonants := consonants + 1;
            end if;
        end if;
        s := @next s;
    end loop;
end sub;

sub example(s: [uint8]) is  
    var vowels: intptr;
    var consonants: intptr;
    (vowels, consonants) := vowels_consonants(s);
    
    print("'");
    print(s);
    print("': ");
    print_i32(vowels as uint32);
    print(" vowels, ");
    print_i32(consonants as uint32);
    print(" consonants.");
    print_nl();
end sub;

example("If not now, then when? If not us, then who?");
Output:
'If not now, then when? If not us, then who?': 10 vowels, 20 consonants.

Delphi

Works with: Delphi version 6.0

Makes extensive use of "sets" to find vowels and consonants and determine if they are unique.

const TestStr1: string = 'Delphi is delightful.';
const TestStr2: string = 'Now is the time for all good men to come to the aid of their country.';


type TCharSet = set of 'a'..'z';

procedure VowelConsonant(S: string; Memo: TMemo);
{Find number of total and unique vowels and consonants}
const Vows: TCharSet = ['a','e','i','o','u'];
const Cons: TCharSet = ['a'..'z']-['a','e','i','o','u'];
var VowSet,ConSet: TCharSet;
var VCnt,CCnt,UVCnt,UCCnt,I: integer;

	procedure HandleMatch(C: char; var Cnt,UCnt: integer; var CSet: TCharSet);
	{Handle set matching and incrementing operations}
	begin
	Inc(Cnt);
	if not (C in CSet) then Inc(UCnt);
	Include(CSet,C);
	end;

begin
Memo.Lines.Add(S);
VCnt:=0; CCnt:=0;
UVCnt:=0;UCCnt:=0;
S:=LowerCase(S);
for I:=1 to Length(S) do
	begin
	{Test if character is vowel or consonant}
	if S[I] in Vows then HandleMatch(S[I],VCnt,UVCnt,VowSet)
	else if S[I] in Cons then HandleMatch(S[I],CCnt,UCCnt,ConSet);
	end;

Memo.Lines.Add('Vowels: '+IntToStr(VCnt));
Memo.Lines.Add('Consonants: '+IntToStr(CCnt));
Memo.Lines.Add('Unique Vowels: '+IntToStr(UVCnt));
Memo.Lines.Add('Unique Consonants: '+IntToStr(UCCnt));
end;


procedure DoVowelConsonantTest(Memo: TMemo);
{Test two strings for vowels/consonants}
begin
VowelConsonant(TestStr1,Memo);
Memo.Lines.Add('');
VowelConsonant(TestStr2,Memo);
end;
Output:
Delphi is delightful.
Vowels: 6
Consonants: 12
Unique Vowels: 3
Unique Consonants: 8

Now is the time for all good men to come to the aid of their country.
Vowels: 22
Consonants: 31
Unique Vowels: 5
Unique Consonants: 13

EasyLang

proc count s$ . .
   for c$ in strchars s$
      c = strcode c$
      if c >= 97 and c <= 122
         c -= 32
      .
      if c >= 65 and c <= 91
         c$ = strchar c
         if c$ = "A" or c$ = "E" or c$ = "I" or c$ = "O" or c$ = "U"
            vow += 1
         else
            cons += 1
         .
      .
   .
   print "There are " & vow & " vowels and " & cons & " consonants"
.
count "Now is the time for all good men to come to the aid of their country."

F#

// Count how many vowels and consonants occur in a string. Nigel Galloway: August 1th., 202
type cType = Vowel |Consonant |Other
let fN g=match g with 'a'|'e'|'i'|'o'|'u'->Vowel |g when System.Char.IsLetter g->Consonant |_->Other
let n="Now is the time for all good men to come to the aid of their country."|>Seq.countBy(System.Char.ToLower>>fN)
printfn "%A" n
Output:
seq [(Consonant, 31); (Vowel, 22); (Other, 16)]

Factor

Works with: Factor version 0.99 2021-06-02
USING: ascii combinators io kernel math.statistics prettyprint
sequences ;

: letter-type ( char -- str )
    {
        { [ dup "aeiouAEIOU" member? ] [ drop "vowel" ] }
        { [ Letter? ] [ "consonant" ] }
        [ "other" ]
    } cond ;

"Forever Factor programming language"
"Now is the time for all good men to come to the aid of their country."
[ dup ... " -> " write [ letter-type ] histogram-by . nl ] bi@
Output:
"Forever Factor programming language"
 -> H{ { "other" 3 } { "consonant" 20 } { "vowel" 12 } }

"Now is the time for all good men to come to the aid of their country."
 -> H{ { "other" 16 } { "consonant" 31 } { "vowel" 22 } }


FreeBASIC

Dim As String cadena = """Forever the FreeBASIC programming language"""
Dim As Integer vocal = 0, consonante = 0

Function isVowel (Byval n As String) As Boolean
    Select Case Asc(n)
    Case 97, 65, 101, 69, 105, 73, 111, 79, 117, 85 'aAeEiIoOuU
        Return True
    Case Else 
        Return False
    End Select
End Function

Function isConsonant (Byval c As String) As Boolean
    Dim As Boolean bool1, bool2, bool3
    bool1 = Not isvowel(c)
    bool2 = (Asc(c) > 64 And Asc(c) < 91)
    bool3 = (Asc(c) > 96 And Asc(c) < 123)
    If bool1 And (bool2 Or bool3) Then
        Return True
    Else
        Return False
    End If
End Function

For n As Integer = 1 To Len(cadena)
    Dim As String letra = Mid(cadena,n,1)
    If isVowel(letra) Then vocal += 1
    If isConsonant(letra) Then consonante += 1
Next n

Print "Input string = "; cadena 
Print "In string occur"; vocal; " vowels" 
Print "In string occur"; consonante; " consonants" 
Sleep
Output:
Input string = "Forever the FreeBASIC programming language"
In string occur 15 vowels
In string occur 23 consonants

FutureBasic

include "NSLog.incl"

void local fn StringGetVowelAndConsonantCount( string as CFStringRef, vowels as ^long, consonents as ^long )
  CFCharacterSetRef vowelSet = fn CharacterSetWithCharactersInString( @"aeiou" )
  CFMutableCharacterSetRef consonantSet = fn MutableCharacterSetLetterSet
  fn MutableCharacterSetRemoveCharactersInString( consonantSet, @"aeiou" )
  *vowels = len( fn StringComponentsSeparatedByCharactersInSet( string, vowelSet ) ) - 1
  *consonents = len( fn StringComponentsSeparatedByCharactersInSet( string, consonantSet ) ) - 1
end fn

void local fn DoIt
  long index, vowels, consonants
  
  CFArrayRef strings = @[@"abcdefghijklmnop345qrstuvwxyz",
  @"The quick brown fox jumps over the lazy dog",
  @"The answer my friend is blowin' in the wind"]
  
  for index = 0 to len(strings) - 1
    fn StringGetVowelAndConsonantCount( strings[index], @vowels, @consonants )
    NSLog(@"\"%@\" contains %ld vowels and %ld consonants",strings[index],vowels,consonants)
  next
end fn

fn Doit

HandleEvents
Output:
"abcdefghijklmnop345qrstuvwxyz" contains 5 vowels and 21 consonants
"The quick brown fox jumps over the lazy dog" contains 11 vowels and 24 consonants
"The answer my friend is blowin' in the wind" contains 11 vowels and 23 consonants

Go

Same approach as the Wren entry.

package main

import (
    "fmt"
    "strings"
)

func main() {
    const (
        vowels     = "aeiou"
        consonants = "bcdfghjklmnpqrstvwxyz"
    )
    strs := []string{
        "Forever Go programming language",
        "Now is the time for all good men to come to the aid of their country.",
    }
    for _, str := range strs {
        fmt.Println(str)
        str = strings.ToLower(str)
        vc, cc := 0, 0
        vmap := make(map[rune]bool)
        cmap := make(map[rune]bool)
        for _, c := range str {
            if strings.ContainsRune(vowels, c) {
                vc++
                vmap[c] = true
            } else if strings.ContainsRune(consonants, c) {
                cc++
                cmap[c] = true
            }
        }
        fmt.Printf("contains (total) %d vowels and %d consonants.\n", vc, cc)
        fmt.Printf("contains (distinct %d vowels and %d consonants.\n\n", len(vmap), len(cmap))
    }
}
Output:
Forever Go programming language
contains (total) 11 vowels and 17 consonants.
contains (distinct 5 vowels and 8 consonants.

Now is the time for all good men to come to the aid of their country.
contains (total) 22 vowels and 31 consonants.
contains (distinct 5 vowels and 13 consonants.

Haskell

The English of the task description is (perhaps unintentionally ?) ambiguous.

One of (at least) four possible meanings here:

import Control.Monad (join)
import Data.Bifunctor (bimap, first, second)
import Data.Bool (bool)
import Data.Char (toUpper)
import qualified Data.Set as S

----- SETS OF UNIQUE VOWELS AND CONSONANTS IN A STRING ---

vowelsAndConsonantsUsed ::
  String -> String -> String -> (S.Set Char, S.Set Char)
vowelsAndConsonantsUsed vowels alphabet =
  foldr
    ( \c vc ->
        if_
          (S.member c vs)
          (first (S.insert c))
          (if_ (S.member c cs) (second (S.insert c)) id)
          vc
    )
    (S.empty, S.empty)
  where
    vs = S.fromList $ vowels <> fmap toUpper vowels
    cs =
      S.fromList $
        filter
          (`S.notMember` vs)
          (alphabet <> fmap toUpper alphabet)

--------------------------- TEST -------------------------
main :: IO ()
main = do
  putStrLn "Unique vowels and consonants used, with counts:\n"
  mapM_ print $
    [(,) . S.toList <*> S.size]
      <*> ( [fst, snd]
              <*> [ vowelsAndConsonantsUsed
                      "aeiou"
                      ['a' .. 'z']
                      "Forever Fortran 2018 programming language"
                  ]
          )

------------------------- GENERAL ------------------------

both :: (a -> b) -> (a, a) -> (b, b)
both = join bimap

if_ :: Bool -> a -> a -> a
if_ p t f =
  if p
    then t
    else f
Output:
Unique vowels and consonants used, with counts:

("aeiou",5)
("Fglmnprtv",9)


Another of (at least) four possible meanings:

import Control.Monad (join)
import Data.Bifunctor (bimap)
import Data.Char (isAlpha)
import Data.List (intercalate, partition)
import qualified Data.Map.Strict as M

------------ COUNTS OF EACH VOWEL AND CONSONANT ----------

vowelAndConsonantCounts ::
  String ->
  ([(Char, Int)], [(Char, Int)])
vowelAndConsonantCounts =
  join bimap M.toList
    . M.partitionWithKey (const . isVowel)
    . fst
    . M.partitionWithKey (const . isAlpha)
    . charCounts

charCounts :: String -> M.Map Char Int
charCounts =
  foldr
    (flip (M.insertWith (+)) 1)
    M.empty

isVowel :: Char -> Bool
isVowel = (`elem` "aeiouAEIOU")

--------------------------- TEST -------------------------
main :: IO ()
main = do
  let (v, c) =
        vowelAndConsonantCounts
          "Forever Fortran 2018 programming language"
      (vTotal, cTotal) =
        both
          (foldr ((+) . snd) 0)
          (v, c)

  putStrLn $
    unlines $
      [ show (vTotal + cTotal)
          <> " 'vowels and consonants'\n"
      ]
        <> fmap
          ('\t' :)
          ( concatMap
              report
              [ ("vowels", vTotal, v),
                ("consonants", cTotal, c)
              ]
          )

------------------------ FORMATTING ----------------------

report :: (String, Int, [(Char, Int)]) -> [String]
report (label, total, xs) =
  [ show total
      <> ( " characters drawn from "
             <> show (length xs)
             <> (' ' : label)
             <> ":"
         )
  ]
    <> (('\t' :) . show <$> xs)
    <> [""]

------------------------- GENERIC ------------------------

both :: (a -> b) -> (a, a) -> (b, b)
both = join bimap
Output:
33 'vowels and consonants'

    12 characters drawn from 5 vowels:
        ('a',4)
        ('e',3)
        ('i',1)
        ('o',3)
        ('u',1)
    
    21 characters drawn from 9 consonants:
        ('F',2)
        ('g',4)
        ('l',1)
        ('m',2)
        ('n',3)
        ('p',1)
        ('r',6)
        ('t',1)
        ('v',1)

J

For this task, we restrict ourselves to english letters, and treat the semivowels (w and y) as consonants.

Implementation (two tallies: vowels first, consonants second):

vowel=: (,toupper) 'aeiou'
consonant=: (,toupper) (a.{~97+i.16) -. vowel
vctally=: e.&vowel ,&(+/) e.&consonant

Examples:

   vctally 'Now is the time for all good men to come to the aid of their country.'
22 18
   vctally 'Forever Action! programming language'
13 13

An alternative expression for consonant could be:

consonant=: (a.#~2|'@Z`z'I.a.) -. vowel

JavaScript

This is a new genre of deliberately ambiguous task description, perhaps ?

I suppose it might be thought to offer scope for variety, but is it really consistent with the core Rosetta goal of comparability ?

(There seem to have been a surprising number of these recently, often associated with tasks of uncertain novelty ...)

Count of "Vowels and Consonants" ?

(() => {
    "use strict";

    // -------- COUNT OF "VOWELS AND CONSONANTS" ---------

    // countOfVowelsAndConsonants :: String -> Int
    const countOfVowelsAndConsonants = s =>
        Array.from(s).filter(isAlpha).length;


    // ---------------------- TEST -----------------------
    const main = () =>
        `${countOfVowelsAndConsonants(
            "Forever Fortran 2018 programming language"
        )} "vowels and consonants"`;


    // --------------------- GENERIC ---------------------

    // isAlpha :: Char -> Bool
    const isAlpha = c =>
        (/[A-Za-z\u00C0-\u00FF]/u).test(c);


    // MAIN ---
    return main();
})();
Output:
33 "vowels and consonants"

Counts of distinct vowels and distinct consonants seen ?

(() => {
    "use strict";

    //  NUMBERS OF DISTINCT VOWELS, AND DISTINCT CONSONANTS

    // distinctVowelsAndConsonants ::
    // String -> ([Char], [Char])
    const distinctVowelsAndConsonants = s =>
        both(
            cs => sort(Array.from(new Set(cs)))
        )(
            partition(isVowel)(
                Array.from(s).filter(isAlpha)
            )
        );

    // ---------------------- TEST -----------------------
    // main :: IO ()
    const main = () => {
        const vc = both(
            cs => `(${cs.join("")}, ${cs.length})`
        )(
            distinctVowelsAndConsonants(
                "Forever Fortran 2018 programming language"
            )
        );

        return [
            `Distinct vowels: ${vc[0]}`,
            `Distict consonants: ${vc[1]}`
        ].join("\n\n");
    };

    // --------------------- GENERIC ---------------------

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a =>
        b => ({
            type: "Tuple",
            "0": a,
            "1": b,
            length: 2
        });


    // both :: (a -> b) -> (a, a) -> (b, b)
    const both = f =>
        ab => Tuple(
            f(ab[0])
        )(
            f(ab[1])
        );


    // isAlpha :: Char -> Bool
    const isAlpha = c =>
        (/[A-Za-z\u00C0-\u00FF]/u).test(c);


    // isVowel :: Char -> Bool
    const isVowel = c =>
        (/[AEIOUaeiou]/u).test(c);


    // partition :: (a -> Bool) -> [a] -> ([a], [a])
    const partition = p =>
        // A tuple of two lists - those elements in
        // xs which match p, and those which do not.
        xs => xs.reduce(
            (a, x) => p(x) ? (
                Tuple(a[0].concat(x))(a[1])
            ) : Tuple(a[0])(a[1].concat(x)),
            Tuple([])([])
        );

    // sort :: Ord a => [a] -> [a]
    const sort = xs =>
        // An A-Z sorted copy of xs.
        xs.slice()
        .sort((a, b) => a < b ? -1 : (a > b ? 1 : 0));


    // MAIN ---
    return main();
})();
Output:
Distinct vowels: (aeiou, 5)

Distict consonants: (Fglmnprtv, 9)

Counts of vowel and consonant occurrences ?

(() => {
    "use strict";

// ---- COUNTS OF VOWEL AND CONSONANT OCCURRENCES ----

    // vowelConsonantOccurrenceTotals :: String -> (Int, Int)
    const vowelConsonantOccurrenceTotals = s =>
        Array.from(s).reduce(
            (ab, c) => (
                isAlpha(c) ? (
                    isVowel(c) ? (
                        first(succ)
                    ) : second(succ)
                ) : identity
            )(ab),
            Tuple(0)(0)
        );

    // ---------------------- TEST -----------------------
    const main = () => {
        const vc =
            vowelConsonantOccurrenceTotals(
                "Forever Fortran 2018 programming language"
            );

        return [
            `Vowel occurrences: ${vc[0]}`,
            `Consonent occurrences: ${vc[1]}`
        ].join("\n\n");
    };


    // --------------------- GENERIC ---------------------

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a =>
        b => ({
            type: "Tuple",
            "0": a,
            "1": b,
            length: 2
        });

    // first :: (a -> b) -> ((a, c) -> (b, c))
    const first = f =>
        // A simple function lifted to one which applies
        // to a tuple, transforming only its first item.
        xy => {
            const tpl = Tuple(f(xy[0]))(xy[1]);

            return Array.isArray(xy) ? (
                Array.from(tpl)
            ) : tpl;
        };

    // identity :: a -> a
    const identity = x =>
        // The identity function.
        x;

    // isAlpha :: Char -> Bool
    const isAlpha = c =>
        (/[A-Za-z\u00C0-\u00FF]/u).test(c);

    // isVowel :: Char -> Bool
    const isVowel = c =>
        (/[AEIOUaeiou]/u).test(c);

    // second :: (a -> b) -> ((c, a) -> (c, b))
    const second = f =>
        // A function over a simple value lifted
        // to a function over a tuple.
        // f (a, b) -> (a, f(b))
        xy => {
            const tpl = Tuple(xy[0])(f(xy[1]));

            return Array.isArray(xy) ? (
                Array.from(tpl)
            ) : tpl;
        };

    // succ :: Int -> Int
    const succ = x =>
        1 + x;

    return main();
})();
Output:
Vowel occurrences: 12

Consonent occurrences: 21

Counts of occurrence for each vowel and consonant ?

(() => {
    "use strict";

    //  COUNTS OF OCCURRENCE FOR EACH VOWEL AND CONSONANT

    // countsOfEachVowelAndConsonant ::
    // String -> ([(Char, Int)], [(Char, Int)])
    const countsOfEachVowelAndConsonant = s =>
        partition(
            cn => isVowel(cn[0])
        )(
            sort(
                Object.entries(
                    charCounts(
                        Array.from(s).filter(isAlpha)
                    )
                )
            )
            .map(([c, n]) => Tuple(c)(n))
        );

    // ---------------------- TEST -----------------------
    const main = () => {
        const report = label =>
            cns => {
                const
                    total = cns.reduce(
                        (a, cn) => a + cn[1],
                        0
                    ),
                    rows = cns.map(
                        compose(s => `\t${s}`, showTuple)
                    ).join("\n");

                return [
                    `${label} counts:\n${rows}`,
                    `\ttotal: ${total}`
                ].join("\n\n");
            };

        const counts = countsOfEachVowelAndConsonant(
            "Forever Fortran 2018 programming language"
        );

        return Array.from(
            bimap(
                report("Vowel")
            )(
                report("Consonant")
            )(
                counts
            )
        ).join("\n\n");
    };


    // --------------------- GENERIC ---------------------

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a =>
        b => ({
            type: "Tuple",
            "0": a,
            "1": b,
            length: 2
        });


    // bimap :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)
    const bimap = f =>
        // Tuple instance of bimap.
        // A tuple of the application of f and g to the
        // first and second values respectively.
        g => tpl => Tuple(f(tpl[0]))(
            g(tpl[1])
        );


    // charCounts :: String -> Dict
    const charCounts = s => {
        // A dictionary of characters seen,
        // with their frequencies.
        const go = (dct, c) =>
            Object.assign(dct, {
                [c]: 1 + (dct[c] || 0)
            });

        return Array.from(s).reduce(go, {});
    };


    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (...fs) =>
        // A function defined by the right-to-left
        // composition of all the functions in fs.
        fs.reduce(
            (f, g) => x => f(g(x)),
            x => x
        );


    // isAlpha :: Char -> Bool
    const isAlpha = c =>
        (/[A-Za-z\u00C0-\u00FF]/u).test(c);


    // isVowel :: Char -> Bool
    const isVowel = c =>
        (/[AEIOUaeiou]/u).test(c);


    // partition :: (a -> Bool) -> [a] -> ([a], [a])
    const partition = p =>
        // A tuple of two lists - those elements in
        // xs which match p, and those which do not.
        xs => xs.reduce(
            (a, x) => p(x) ? (
                Tuple(a[0].concat(x))(a[1])
            ) : Tuple(a[0])(a[1].concat(x)),
            Tuple([])([])
        );


    // sort :: Ord a => [a] -> [a]
    const sort = xs =>
        // An A-Z sorted copy of xs.
        xs.slice()
        .sort((a, b) => a < b ? -1 : (a > b ? 1 : 0));


    // showTuple :: Tuple -> String
    const showTuple = tpl =>
        `(${tpl[0]}, ${tpl[1]})`;


    // MAIN ---
    return main();
})();
Output:
Vowel counts:
    (a, 4)
    (e, 3)
    (i, 1)
    (o, 3)
    (u, 1)

    total: 12

Consonant counts:
    (F, 2)
    (g, 4)
    (l, 1)
    (m, 2)
    (n, 3)
    (p, 1)
    (r, 6)
    (t, 1)
    (v, 1)

    total: 21

jq

Works with: jq

Works with gojq, the Go implementation of jq

This entry focuses solely on the A-Z alphabet.

def is_lowercase_vowel: IN("a","e","i","o","u");
def is_lowercase_letter: "a" <= . and . <= "z";
def is_lowercase_consonant: is_lowercase_letter and (is_lowercase_vowel|not);

def synopsis:
  # Output: a stream of the constituent characters
  def characters: ascii_downcase | explode[] | [.] | implode;
  # For the sake of DRYness:
  def s(stream; $vowels; $consonants): 
    reduce stream as $c ({($vowels): 0, ($consonants):0};
      if $c|is_lowercase_vowel then .[$vowels] += 1 
      elif $c|is_lowercase_consonant then .[$consonants] += 1
      else . end);

    s( characters; "vowels"; "consonants" )
  + s( [characters]|unique[]; "distinct_vowels"; "distinct_consonants" );

def task:
  def pp: "Synopsis for:", ., synopsis;

  "Forever HOPL",
  "Now is the time for all good men to come to the aid of their country."
  | pp, "";

task
Output:
Synopsis for:
Forever HOPL
{
  "vowels": 4,
  "consonants": 7,
  "distinct_vowels": 2,
  "distinct_consonants": 6
}

Synopsis for:
Now is the time for all good men to come to the aid of their country.
{
  "vowels": 22,
  "consonants": 31,
  "distinct_vowels": 5,
  "distinct_consonants": 13
}


Julia

isvowel(c) = c in ['a', 'e', 'i', 'o', 'u', 'A', 'E', "I", 'O', 'U']
isletter(c) = 'a' <= c <= 'z' || 'A' <= c <= 'Z'
isconsonant(c) = !isvowel(c) && isletter(c)

function vccounts(s)
    a = collect(lowercase(s))
    au = unique(a)
    count(isvowel, a), count(isconsonant, a), count(isvowel, au), count(isconsonant, au)
end

function testvccount()
    teststrings = [
        "Forever Julia programming language",
        "Now is the time for all good men to come to the aid of their country."]
    for s in teststrings
        vcnt, ccnt, vu, cu = vccounts(s)
        println("String: $s\n    Vowels: $vcnt (distinct $vu)\n    Consonants: $ccnt (distinct $cu)\n")
    end
end

testvccount()
Output:
String: Forever Julia programming language
    Vowels: 13 (distinct 5)
    Consonants: 18 (distinct 9)

String: Now is the time for all good men to come to the aid of their country.
    Vowels: 22 (distinct 5)
    Consonants: 31 (distinct 13)

Ksh

#!/bin/ksh

# Count how many vowels and consonants occur in a string

#	# Variables:
#
string1="Now is the time for all good men to come to the aid of their country."
string=${1:-${string1}}		# Allow command line input

consonant="b|c|d|f|g|h|j|k|l|m|n|p|q|r|s|t|v|w|x|y|z"
vowel="a|e|i|o|u"

integer i rc
typeset -ia lettercnt uniquecnt
typeset -a letlist

#	# Functions:
#
#	# Function _vorc(ch) - Return 0 if consonant; 1 if vowel; 99 else
#
function _vorc {
	typeset _ch ; typeset -l _char="$1"

	[[ "${_char}" == @(${consonant}) ]] && return 0
	[[ "${_char}" == @(${vowel}) ]] && return 1
	return 99
}

#	# Function _uniq(char, type, list, arr) - increment arr[] if chart not in list[]
#
function _uniq {
	typeset _char ; _char="$1"
	typeset _type ; integer _type=$2
	typeset _list ; nameref _list="$3"
	typeset _arr  ; nameref _arr="$4"

	if [[ "${_char}" != @(${_list[_type]% *}) ]]; then
		_list[_type]+="${_char}|"		# Add letter to the proper list
		(( _arr[_type]++ ))				# Increment uniq counter
	fi
}

 ######
# main #
 ######

echo "${string}" | while read ; do
	for ((i=0; i<${#REPLY}; i++)); do
		char="${REPLY:${i}:1}"
		_vorc "${char}" ; rc=$?
		(( rc != 99 )) && (( lettercnt[rc]++ )) && _uniq "${char}" ${rc} letlist uniquecnt
	done
done

printf "\n%s\n\n" "${string}"
printf "Consonants: %3d  (Unique: %2d)\n" "${lettercnt[0]}" "${uniquecnt[0]}"
printf "   Vowlels: %3d  (Unique: %2d)\n" "${lettercnt[1]}" "${uniquecnt[1]}"
Output:
Now is the time for all good men to come to the aid of their country.

Consonants:  31  (Unique: 13)
   Vowlels:  22  (Unique:  5)

Mathematica/Wolfram Language

vowels = {"a", "e", "i", "o", "u"};
conso = {"b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z"};
vowels = Join[vowels, ToUpperCase@vowels];
conso = Join[conso, ToUpperCase@conso];
str = "The universe is under no obligation to make sense to you.";
<|"vowels" -> StringCount[str, Alternatives @@ vowels], 
 "consonants" -> StringCount[str, Alternatives @@ conso], 
 "other" -> StringCount[str, Except[Alternatives @@ Join[vowels, conso]]]|>
Output:
<|"vowels" -> 22, "consonants" -> 24, "other" -> 11|>

Modula-2

MODULE VowelsAndConsonants;
FROM InOut IMPORT WriteString, WriteCard, WriteLn;
FROM Strings IMPORT Length;

PROCEDURE uppercase(c: CHAR): CHAR;
BEGIN
    IF (c >= 'a') AND (c <= 'z') THEN
        c := CHR(ORD(c) - 32);
    END;
    RETURN c;
END uppercase;

PROCEDURE CountVowelsAndConsonants(s: ARRAY OF CHAR; VAR v, c: CARDINAL);
    VAR i, length: CARDINAL;
        ch: CHAR;
BEGIN
    v := 0;
    c := 0;
    length := Length(s);
    IF length > 0 THEN
        FOR i := 0 TO length-1 DO
            ch := uppercase(s[i]);
            IF (ch >= 'A') AND (ch <= 'Z') THEN
                IF (ch = 'A') 
                OR (ch = 'E') 
                OR (ch = 'I') 
                OR (ch = 'O') 
                OR (ch = 'U') THEN
                    INC(v);
                ELSE
                    INC(c);
                END;
            END;
        END;
    END;
END CountVowelsAndConsonants;

PROCEDURE Display(s: ARRAY OF CHAR);
    VAR v, c: CARDINAL;
BEGIN
    WriteString('"');
    WriteString(s);
    WriteString('": ');
    CountVowelsAndConsonants(s, v, c);
    WriteCard(v, 0);
    WriteString(' vowels, ');
    WriteCard(c, 0);
    WriteString(' consonants.');
    WriteLn;
END Display;

BEGIN
    Display("If not now, then when? If not us, then who?");
END VowelsAndConsonants.
Output:
"If not now, then when? If not us, then who?": 10 vowels, 20 consonants.

Nim

import strutils

const
  Vowels = {'a', 'e', 'i', 'o', 'u'}
  Consonants = {'a'..'z'} - Vowels

func value(val: int; unit: string): string =
  $val & ' ' & unit & (if val > 1: "s" else: "")

proc vcCount(text: string) =
  var vowels, consonants: set[char]
  var vowelCount, consonantCount = 0
  for c in text.toLowerAscii:
    if c in Consonants:
      consonants.incl c
      inc consonantCount
    elif c in Vowels:
      vowels.incl c
      inc vowelCount
  echo "“$#” contains" % text
  echo "    $1 and $2 (distinct)".format(value(vowels.card, "vowel"),
                                         value(consonants.card, "consonant"))
  echo "    $1 and $2 (total)".format(value(vowelCount, "vowel"),
                                      value(consonantCount, "consonant"))

vcCount("Now is the time for all good men to come to the aid of their country.")
Output:
“Now is the time for all good men to come to the aid of their country.” contains
    5 vowels and 13 consonants (distinct)
    22 vowels and 31 consonants (total)

Pascal

Standard “Unextended” Pascal (ISO standard 7185) does not really know the notion of strings:

program countHowManyVowelsAndConsonantsOccurInAString(input, output);

var
	vowel, consonant: set of char;
	vowelCount, consonantCount: integer;

begin
	{ initialize variables  - - - - - - - - - - - - - - - - - - }
	vowel := ['A', 'E', 'I', 'O', 'U', 'a', 'e', 'i', 'o', 'u'];
	consonant := ['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L',
		'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Y',
		'Z', 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm',
		'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z'];
	
	vowelCount := 0;
	consonantCount := 0;
	
	{ process - - - - - - - - - - - - - - - - - - - - - - - - - }
	while not EOF do
	begin
		{ input^ refers to the buffer variable's value }
		vowelCount     := vowelCount     + ord(input^ in vowel);
		consonantCount := consonantCount + ord(input^ in consonant);
		get(input)
	end;
	
	{ result  - - - - - - - - - - - - - - - - - - - - - - - - - }
	writeLn(vowelCount,     ' vowels');
	writeLn(consonantCount, ' consonants')
end.
Input:
The quick brown fox jumps over the lazy dog.
Output:
         11 vowels
         24 consonants

Perl

#!/usr/bin/perl

use strict; # https://rosettacode.org/wiki/Count_how_many_vowels_and_consonants_occur_in_a_string
use warnings;

while( <DATA> )
  {
  print "@{[ $- = tr/aeiouAEIOU// ]} vowels @{[ tr/a-zA-Z// - $-
    ]} consonants in: $_\n"
  }

__DATA__
test one
TEST ONE
Now is the time for all good men to come to the aid of their country.
Forever Perl Programming Language
Output:
3 vowels 4 consonants in: test one

3 vowels 4 consonants in: TEST ONE

22 vowels 31 consonants in: Now is the time for all good men to come to the aid of their country.

11 vowels 19 consonants in: Forever Perl Programming Language


Phix

with javascript_semantics
procedure count_vowels_and_consonants(string s)
    constant vco = {"vowels","consonants","other"}, fvco = {"%d %s (%d distinct)"}
    sequence r = sort(filter(apply(true,find,{lower(s),{"aeioubcdfghjklmnpqrstvwxyz"}}),"!=",0))
    integer v = abs(binary_search(6,r))-1, uv = length(unique(r[1..v])),
            c = length(r)-v,               uc = length(unique(r[v+1..$])),
            o = length(s)-length(r),       uo = length(unique(lower(s)))-(uv+uc)
    string {sv,sc,so} = apply(true,sprintf,{fvco,columnize({{v,c,o},vco,{uv,uc,uo}})})
    printf(1,"The string \"%s\"\n  contains %s, %s, and %s.\n",{s,sv,sc,so})
end procedure
count_vowels_and_consonants("Now is the time for all good men to come to the aid of their country.")
Output:
The string "Now is the time for all good men to come to the aid of their country."
  contains 22 vowels (5 distinct), 31 consonants (13 distinct), and 16 other (2 distinct).

Picat

List comprehension

Also using maps for counting individual characters.

main =>
  S = "Count how many vowels and consonants occur in a string",
  vowels(Vowels),
  consonants(Consonants),
  CountVowels = [C : C in S, membchk(C,Vowels)].len,
  CountConsonants = [C : C in S, membchk(C,Consonants)].len,
  
  println([vowels=CountVowels,consonants=CountConsonants,rest=(S.len-CountVowels-CountConsonants)]),
  nl,

  % Occurrences of each character
  println(all=count_chars(S)),
  println(vowels=count_chars(S,Vowels)),
  println(consonants=count_chars(S,Consonants)),    
  nl.

vowels("aeiouAEIOU").
consonants("bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ").

count_chars(S) = count_chars(S,"").
count_chars(S,Cs) = Map =>
  Map = new_map(),
  foreach(C in S, (Cs != "" -> membchk(C,Cs) ; true))
    Map.put(C,Map.get(C,0)+1)
  end.
Output:
[vowels = 15,consonants = 30,rest = 9]

all = (map)[m = 1,s = 4,w = 2,C = 1,e = 1,c = 3,h = 1,n = 8,u = 2,t = 3,a = 4,d = 1,i = 2,l = 1,o = 6,r = 2,v = 1,y = 1,  = 9,g = 1]
vowels = (map)[u = 2,i = 2,o = 6,a = 4,e = 1]
consonants = (map)[m = 1,s = 4,w = 2,C = 1,c = 3,h = 1,n = 8,t = 3,d = 1,l = 1,r = 2,v = 1,y = 1,g = 1]

Recursion

main =>
  S = "Count how many vowels and consonants occur in a string",
  vowels(Vowels),
  consonants(Consonants),
  NumVowels = count_set(Vowels,S),
  NumConsonants = count_set(Consonants,S),
  NumRest = S.len - NumVowels - NumConsonants,
  println([vowels=NumVowels,consontants=NumConsonants,rest=NumRest]),
  nl.
  
vowels("aeiouAEIOU").
consonants("bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ").

count_set(Set,S) = Vs =>
  count_set(Set,S,0,Vs).
count_set(_Set,[],Vs,Vs).
count_set(Set,[C|Cs],Vs0,Vs) :-
  (membchk(C,Set) ->
    Vs1 = Vs0 + 1
   ;
    Vs1 = Vs0
  ),
  count_set(Set,Cs,Vs1,Vs).
Output:
[vowels = 15,consontants = 30,rest = 9]

Plain English

To run:
Start up.
Put "Now is the time for all good men to come to the aid of their country." into a string.
Find a vowel count and a consonant count of the string.
Write the double-quote byte then the string then the double-quote byte on the console.
Write "Number of vowels: " then the vowel count on the console.
Write "Number of consonants: " then the consonant count on the console.
Wait for the escape key.
Shut down.

To find a vowel count and a consonant count of a string:
Slap a substring on the string.
Loop.
If the substring is blank, exit.
Put the substring's first's target into a letter.
If the letter is any vowel, bump the vowel count.
If the letter is any consonant, bump the consonant count.
Add 1 to the substring's first.
Repeat.
Output:
"Now is the time for all good men to come to the aid of their country."
Number of vowels: 22
Number of consonants: 31

Python

Translation of: Julia
def isvowel(c):
    """ true if c is an English vowel (ignore y) """
    return c in ['a', 'e', 'i', 'o', 'u', 'A', 'E', "I", 'O', 'U']

def isletter(c):
    """ true if in English standard alphabet """
    return 'a' <= c <= 'z' or 'A' <= c <= 'Z'

def isconsonant(c):
    """ true if an English consonant """
    return  not isvowel(c) and isletter(c)

def vccounts(s):
    """ case insensitive vowel counts, total and unique """
    a = list(s.lower())
    au = set(a)
    return sum([isvowel(c) for c in a]), sum([isconsonant(c) for c in a]), \
        sum([isvowel(c) for c in au]), sum([isconsonant(c) for c in au])

def testvccount():
    teststrings = [
        "Forever Python programming language",
        "Now is the time for all good men to come to the aid of their country."]
    for s in teststrings:
        vcnt, ccnt, vu, cu = vccounts(s)
        print(f"String: {s}\n    Vowels: {vcnt} (distinct {vu})\n    Consonants: {ccnt} (distinct {cu})\n")

testvccount()
Output:

String: Forever Python programming language

   Vowels: 11 (distinct 5)
   Consonants: 21 (distinct 11)

String: Now is the time for all good men to come to the aid of their country.

   Vowels: 22 (distinct 5)
   Consonants: 31 (distinct 13)


Or, selecting another of the various possible meanings of an ambiguous task description:

'''Total and individual counts of vowel and consonant instances'''

from functools import reduce


# vowelAndConsonantCounts :: String ->
#   ([(Char, Int)], [(Char, Int)])
def vowelAndConsonantCounts(s):
    '''The sorted character counts for each
       vowel seen in the string, tupled with the sorted
       character counts for each consonant seen.
    '''
    return both(sorted)(
        partition(lambda kv: isVowel(kv[0]))([
            (k, v) for (k, v) in list(charCounts(s).items())
            if k.isalpha()
        ])
    )


# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    '''Total and individual counts for a given string'''

    vs, cs = vowelAndConsonantCounts(
        "Forever Fortran 2018 programming language"
    )
    nv, nc = valueSum(vs), valueSum(cs)
    print(f'{nv + nc} "vowels and consonants"\n')

    print(f'\t{nv} characters drawn from {len(vs)} vowels:')
    print(showCharCounts(vs))
    print(f'\n\t{nc} characters drawn from {len(cs)} consonants:')
    print(showCharCounts(cs))


# ----------------------- DISPLAY ------------------------

# showCharCounts :: [(Char, Int)] -> String
def showCharCounts(kvs):
    '''Indented listing of character frequencies.
    '''
    return '\n'.join(['\t\t' + repr(kv) for kv in kvs])


# ----------------------- GENERIC ------------------------

# both :: (a -> b) -> (a,  a) -> (b,  b)
def both(f):
    '''The same function applied to both
       values of a tuple.
    '''
    def go(ab):
        return f(ab[0]), f(ab[1])
    return go


# charCount :: String -> Dict
def charCounts(s):
    '''A dictionary of characters seen,
       with their frequencies.
    '''
    def go(dct, c):
        dct.update({c: 1 + dct.get(c, 0)})
        return dct

    return reduce(go, list(s), dict())


# isVowel :: Char -> Bool
def isVowel(c):
    '''True if the character is an Anglo-Saxon vowel'''
    return c in "aeiouAEIOU"


# partition :: (a -> Bool) -> [a] -> ([a], [a])
def partition(p):
    '''The pair of lists of those elements in xs
       which respectively do, and don't
       satisfy the predicate p.
    '''
    def go(a, x):
        ts, fs = a
        return (ts + [x], fs) if p(x) else (ts, fs + [x])
    return lambda xs: reduce(go, xs, ([], []))


# valueSum :: [(String, Int)] -> Int
def valueSum(kvs):
    '''The sum of values in a [(key, value)] list'''
    return sum(kv[1] for kv in kvs)


# MAIN ---
if __name__ == '__main__':
    main()
Output:
33 "vowels and consonants"

    12 characters drawn from 5 vowels:
        ('a', 4)
        ('e', 3)
        ('i', 1)
        ('o', 3)
        ('u', 1)

    21 characters drawn from 9 consonants:
        ('F', 2)
        ('g', 4)
        ('l', 1)
        ('m', 2)
        ('n', 3)
        ('p', 1)
        ('r', 6)
        ('t', 1)
        ('v', 1)

Quackery

  [ bit 
    [ 0 $ "AEIOUaeiuo"
      witheach [ bit | ] ] constant 
     & 0 != ]                        is vowel     ( c --> b   )

  [ bit 
    [ 0 $ "BCDFGHJKLMNPQRSTVWXYZ"
      $ "bcdfghjklmnpqrstvwxyz" join
      witheach [ bit | ] ] constant 
     & 0 != ]                        is consonant ( c --> b   )

  [ 0 0 rot witheach
      [ tuck vowel +
        dip [ consonant + ] ] ]      is task      ( $ --> n n )
 
  $ "How fleeting are all human passions compared" 
  $ " with the massive continuity of ducks." join
  
  task 
 
  echo say " vowels" cr
  echo say " consonants"
Output:
26 vowels
43 consonants

OR, depending on how you interpret the task…

  [ 0 $ "AEIOU" 
    witheach [ bit | ] ] constant      is vowels     (   --> n   )

  [ 0 $ "BCDFGHJKLMNPQRSTVWXYZ"
      witheach [ bit | ] ] constant    is consonants (   --> n   )

  [ 0 swap 
    [ dup 0 > while
      tuck 1 & + 
     swap 1 >> again ] 
    drop ]                            is bitcount    ( n --> n   )

 [ 0 swap witheach [ upper bit | ] 
   dup consonants & bitcount
   swap vowels & bitcount ]           is task        ( $ --> n n ) 

  $ "How fleeting are all human passions compared" 
  $ " with the massive continuity of ducks." join
  
  task 
 
  echo say " distinct vowels" cr
  echo say " distinct consonants"
Output:
5 distinct vowels
16 distinct consonants

Raku

Note that the task does not ask for the total count of vowels and consonants, but for how many occur.

my @vowels     = <a e i o u>;
my @consonants = <b c d f g h j k l m n p q r s t v w x y z>;

sub letter-check ($string) {
    my $letters = $string.lc.comb.Set;
    "{sum $letters{@vowels}} vowels and {sum $letters{@consonants}} consonants occur in the string \"$string\"";
}

say letter-check "Forever Ring Programming Language";
Output:
5 vowels and 8 consonants occur in the string "Forever Ring Programming Language"

REBOL

REBOL [
	Title: "Count how many vowels and consonants occur in a string"
	Date: 21-Dec-2022
	Author: "Earldridge Jazzed Pineda"
]

countVowelsConsonants: func [string] [
	vowels: [#"a" #"e" #"i" #"o" #"u"]
	consonants: [#"b" #"c" #"d" #"f" #"g" #"h" #"j" #"k" #"l" #"m" #"n" #"p" #"q" #"r" #"s" #"t" #"v" #"w" #"x" #"y" #"z"]

	vowelCount: 0
	consonantCount: 0

	foreach character string [
		if (find consonants character) <> none [consonantCount: consonantCount + 1]
		if (find vowels character) <> none [vowelCount: vowelCount + 1]
	]
	

	return reduce [vowelCount consonantCount]
]

string: "Count how many vowels and consonants occur in a string"
counts: countVowelsConsonants string
print [mold string "has" pick counts 1 "vowels and" pick counts 2 "consonants"]
Output:
{Count how many vowels and consonants occur in a string} has 15 vowels and 30 consonants

REXX

version 1

/* REXX */
Parse Arg s
If s='' Then
  s='Forever Wren programming language'
con='BCDFGHJKLMNPQRSTVWXYZ'
vow='AEIOU'
su=translate(s)             /* translate to uppercase             */
suc=su
sx=''                       /* eliminate duplicate characters     */
Do While suc<>''
  Parse Var suc c +1 suc
  If pos(c,sx)=0 Then sx=sx||c
  End
Say s                       /* show input string                  */
Call count su               /* count all consonants and vowels    */
Call count sx,'distinct'    /* count unique consonants and vowels */
Exit
count:
Parse Arg s,tag
sc=translate(s,copies('+',length(con))copies(' ',256),con||xrange('00'x,'ff'x))
sv=translate(s,copies('+',length(vow))copies(' ',256),vow||xrange('00'x,'ff'x))
Say length(space(sc,0)) tag 'consonants,' length(space(sv,0)) tag 'vowels'
Return
Output:
Forever Wren programming language
19  consonants, 11  vowels
9 distinct consonants, 5 distinct vowels

version 2

/*REXX program counts the vowels and consonants  (unique and total)  in a given string. */
parse arg $                                      /*obtain optional argument from the CL.*/
if $=''  then $= 'Now is the time for all good men to come to the aid of their country.'
say 'input: '  $                                 /*display the original string ──► term.*/
call init                                        /*initialize some constants and input. */
#.= 0;        call cnt 1;      call cnt 2        /*count unique vowels  and  consonants.*/
say 'There are '    #.1   " unique vowels,  there are "     #.2     ' unique consonants.'
say 'There are '    L - length( space( translate($, , @.1), 0))     " vowels total, "    ,
    'there are '    L - length( space( translate($, , @.2), 0))     " consonants total."
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
cnt: arg k; do j=1 to length(@.k); if pos(substr(@.k,j,1),$)>0 then #.k=#.k+1; end; return
init: @.1='AEIOU'; @.2="BCDFGHJKLMNPQRSTVWXYZ"; upper $; $=space($,0); L=length($); return
output   when using the default input:
input:  Now is the time for all good men to come to the aid of their country.
There are  5  unique vowels,  there are  13  unique consonants.
There are  22  vowels total,  there are  31  consonants total.

Ring

? "working..."
str = '"' + "Forever Ring Programming Language" + '"'
vowel = 0 vowels = [] for x in "AEIOUaeiou" add(vowels, x) next
ltrc = 0 all = 'A':'z' while all[27] != 'a' del(all, 27) end

for n in str
    if find(vowels, n) > 0 vowel++ ok
    if find(all, n) > 0 ltrc++ ok
next

? "Input string = " + str
? "In string occur " + vowel + " vowels"
? "In string occur " + (ltrc - vowel)  + " consonants"
put "done..."
Output:
working...
Input string = "Forever Ring Programming Language"
In string occur 11 vowels
In string occur 19 consonants
done...

RPL

Works with: Halcyon Calc version 4.2.8
≪ "AEIOU" → str voy 
   ≪ (0,0) 1 str SIZE FOR j 
         str j DUP SUB 
         IF DUP "a" ≥ OVER "z" ≤ AND THEN NUM 32 - CHR END 
         IF DUP "A" ≥ OVER "Z" ≤ AND THEN voy SWAP POS 1 (0,1) IFTE + ELSE DROP END 
      NEXT 
≫ ≫ 'VOYCON' STO
"Now is the time for all good men to come to the aid of their country." VOYCON
Output:
1: (22,31)

Ruby

RE_V = /[aeiou]/
RE_C = /[bcdfghjklmnpqrstvwxyz]/
str  = "Now is the time for all good men to come to the aid of their country."

grouped = str.downcase.chars.group_by do |c|
  case c
    when RE_V then :Vowels
    when RE_C then :Consonants
    else :Other
  end
end

grouped.each{|k,v| puts "#{k}: #{v.size}, #{v.uniq.size} unique."}
Output:
Consonants: 31, 13 unique.
Vowels: 22, 5 unique.
Other: 16, 2 unique.

SNOBOL4

* Program: countvc.sbl,
* To run: sbl countvc.sbl
* Description: Count how many vowels and consonants occur in a string
* Comment: Tested using the Spitbol for Linux version of SNOBOL4


* Function SQUEEZE will remove some characters from s (string).
* Parameter c is the character set to keep or remove.
* If parameter kr is 1, then only characters in c will be kept.
* If it is 0, then the characters in c will be removed.
* Parameter kr defaults to 1. So if it is null or not 0 or 1,
* then it becomes 1.
    define('squeeze(s,c,kr)pre')
    :(squeeze_end)
squeeze
    kr = (eq(size(kr),0) 1,kr)
    kr = (eq(kr,1) kr, eq(kr,0) kr, 1)
    eq(kr,1) :s(kr1)
kr0
* Exclude character set
    s ? breakx(c) . pre span(c) = :f(kr2)
    squeeze = squeeze pre
    :(kr0)
kr1
* Include character set
    s ? breakx(c) span(c) . pre = :f(kr2)
    squeeze = squeeze pre
    :(kr1)
kr2
    :(return)
squeeze_end


* Function POPT will populate table t with counts
* for each, unique character from string.
* It first standarizes string to only contain
* upper and lower case letters and then replaces
* upper case letters with lower case letters.
* It returns t converted to an array.
    define('popt(string,t)s,c') :(popt_end)
popt
    s = squeeze(string,&lcase &ucase)
    s = replace(s,&ucase,&lcase)
popt1
    s ? len(1) . c = ?(t[c] = t[c] + 1) :s(popt1)
    popt = convert(t,'ARRAY') :s(return)f(freturn)
popt_end


* Function OUTPUTARRAY will output array as well as return the number
* of unique array elements and the sum of their counts,
* separated by the |.
    define('outputarray(a)i,sum,n') :(outputarray_end)
outputarray
    i = i + 1
    output = a[i,1] ', ' a[i,2] :f(outputarray2)
    sum = sum + a[i,2]
    n = i
    :(outputarray)
outputarray2
    outputarray = n "|" sum
    :(return)
outputarray_end


    alphabet = &lcase &ucase
    vowels = 'aeiouAEIOU'
    consonants = squeeze(alphabet,vowels,0)  ;* Remove vowels

    v = table()
    c = table()

    s = "Now is the time for all good men to come to the aid of their country."

	output = s

    vs = squeeze(s,vowels,1)      ;* Remove all characters if not a vowel
    va = popt(vs,v)               ;* Put unique characters into array with counts
    ret = outputarray(va)         ;* Output character array
    ret ? breakx("|") . n len(1) rem . sum
    output = "Number of unique vowels is " n ', total=' sum

    cs = squeeze(s,consonants,1)  ;* Remove all characters if not a consonant
    vc = popt(cs,c)               ;* Put unique characters into array with counts
    ret = outputarray(vc)         ;* Output character array
    ret ? breakx("|") . n len(1) rem . sum
    output = "Number of unique consonants is " n ', total=' sum

END
Output:
Now is the time for all good men to come to the aid of their country.
o, 9
i, 4
e, 6
a, 2
u, 1
Number of unique vowels is 5, total=22
n, 3
w, 1
s, 1
t, 7
h, 3
m, 3
f, 2
r, 3
l, 2
g, 1
d, 2
c, 2
y, 1
Number of unique consonants is 13, total=31

Wren

Library: Wren-str

In the absence of any indications to the contrary, we take a simplistic view of only considering English ASCII vowels (not 'y') and consonants.

import "./str" for Str

var vowels = "aeiou"
var consonants = "bcdfghjklmnpqrstvwxyz"

var strs = [
    "Forever Wren programming language",
    "Now is the time for all good men to come to the aid of their country."
]

for (str in strs) {
    System.print(str)
    str = Str.lower(str)
    var vc = 0
    var cc = 0
    var vmap = {}
    var cmap = {}
    for (c in str) {
        if (vowels.contains(c)) {
            vc = vc  + 1
            vmap[c] = true
        } else if (consonants.contains(c)) {
            cc = cc + 1
            cmap[c] = true
        }
    }
    System.print("contains (total) %(vc) vowels and %(cc) consonants.")
    System.print("contains (distinct) %(vmap.count) vowels and %(cmap.count) consonants.\n")
}
Output:
Forever Wren programming language
contains (total) 11 vowels and 19 consonants.
contains (distinct) 5 vowels and 9 consonants.

Now is the time for all good men to come to the aid of their country.
contains (total) 22 vowels and 31 consonants.
contains (distinct) 5 vowels and 13 consonants.

X86 Assembly

Translation of XPL0. Assemble with tasm, tlink /t

        .model  tiny
        .code
        .486
        org     100h

;Register assignments:
;al  = Char
;ebx = CSet
;cl  = CTC
;ch  = VTC
;dl  = CDC
;dh  = VDC
;si  = Str
;edi = VSet
;ebp = Item

start:  mov     si, offset str1 ;Text(Str1)
        call    vowcon
        mov     si, offset str2 ;Text(Str2)

;Display numbers of vowels and consonants in string at si
vowcon: push    si
        xor     cx, cx          ;CTC:= 0;  VTC:= 0
        xor     dx, dx
        xor     ebx, ebx
        xor     edi, edi

;while Str(I) # 0 do
; Ch:= Str(I); I++
cv10:   lodsb                   ;al:= ds:[si++]
        cmp     al, 0
        je      cv90            ; if Ch>=^A & Ch<=^Z then
        cmp     al, 'A'
        jb      cv20
         cmp    al, 'Z'
         ja     cv20
          or    al, 20h         ;  Ch:= Ch ! $20
cv20:
        cmp     al, 'a'         ; if Ch>=^a & Ch<=^z then
        jb      cv50
        cmp     al, 'z'
        ja      cv50

        push    cx              ;  Item:= 1 << (Ch-^a)
        mov     cl, al
        sub     cl, 'a'
        xor     ebp, ebp        ;  mov ebp, 1
        inc     bp
        shl     ebp, cl
        pop     cx

        cmp     al, 'a'         ;  case Ch of a e i o u vowels
        je      cv22
        cmp     al, 'e'
        je      cv22
        cmp     al, 'i'
        je      cv22
        cmp     al, 'o'
        je      cv22
        cmp     al, 'u'
        jne     cv30

cv22:   inc     ch              ;    VTC++
        test    edi, ebp        ;    if (VSet&Item) = 0 then
        jne     cv25
         inc    dh              ;     VDC++
         or     edi, ebp        ;     VSet:= VSet ! Item
cv25:   jmp     cv50
cv30:                           ;  other: consonants
        inc     cl              ;    CTC++
        test    ebx, ebp        ;    if (CSet&Item) = 0 then
        jne     cv50
         inc    dl              ;     CDC++
         or     ebx, ebp        ;     CSet:= CSet ! Item
cv50:   jmp     cv10
cv90:
        pop     si
        call    strout
        mov     si, offset crlf ;CrLf
        call    strout
        mov     di, offset msg2 ;Text(" total")
        call    common

        mov     cx, dx          ;get distinct counts
        mov     di, offset msg2a;Text(" distinct")
        call    common
        mov     si, offset crlf
        jmp     strout

;Common display code
common: mov     si, offset msg1 ;Text("Contains ")
        call    strout
        mov     al, ch          ;numout(VTC/VDC)
        call    numout
        mov     si, di          ;Text(" total/distinct")
        call    strout
        mov     si, offset msg3 ;Text(" vowels and ")
        call    strout
        mov     al, cl          ;numout(CTC/CDC)
        call    numout
        mov     si, offset msg4 ;Text(" consonants.^M^J")
        jmp     strout

;Display string pointed to by si
so10:   int     29h
strout: lodsb                   ;al:= ds:[si++]
        cmp     al, 0
        jne     so10
        ret

;Display positive number in al (less than 100)
numout: aam     10      ;ah:= al/10; al:= rem
        push    ax
        test    ah, ah
        je      no10
         mov    al, ah
         call   numout
no10:   pop     ax
        add     al, '0'
        int     29h
        ret

str1    db      "X86 Assembly Language!", 0
str2    db      "Now is the time for all good men to come to the aid of their country.", 0
msg1    db      "Contains ", 0
msg2    db      " total", 0
msg2a   db      " distinct", 0
msg3    db      " vowels and ", 0
msg4    db      " consonants."
crlf    db      0Dh, 0Ah, 0
        end     start
Output:
X86 Assembly Language!
Contains 6 total vowels and 11 consonants.
Contains 3 distinct vowels and 8 consonants.

Now is the time for all good men to come to the aid of their country.
Contains 22 total vowels and 31 consonants.
Contains 5 distinct vowels and 13 consonants.

XPL0

string 0;               \use zero-terminated strings
int  VTC, VDC,          \vowel total count, vowel distinct count
     CTC, CDC,          \consonant total count, consonant distinct count
     VSet, CSet,        \vowel and consonant bit arrays
     Char, Item, I, J;
char Str;
[Str:= ["Forever XPL0 programming language.",
        "Now is the time for all good men to come to the aid of their country."];
for J:= 0 to 1 do
    [I:= 0;  VTC:= 0;  VDC:= 0;  CTC:= 0;  CDC:= 0;  VSet:= 0;  CSet:= 0;
    while Str(J,I) do
        [Char:= Str(J,I);  I:= I+1;
        if Char>=^A & Char<=^Z then
            Char:= Char - ^A + ^a;      \to lower case
        if Char>=^a & Char<=^z then
            [Item:= 1 << (Char-^a);     \item in character set [a..z]
            case Char of
                ^a, ^e, ^i, ^o, ^u:
                    [VTC:= VTC+1;       \vowel
                    if (Item & VSet) = 0 then VDC:= VDC+1;
                    VSet:= VSet ! Item;
                    ]
            other   [CTC:= CTC+1;       \consonant
                    if (Item & CSet) = 0 then CDC:= CDC+1;
                    CSet:= CSet ! Item;
                    ];
            ];
        ];
    Text(0, @Str(J,0));  CrLf(0);
    Text(0, "Contains ");  IntOut(0, VTC);  Text(0, " total vowels and ");
    IntOut(0, CTC);  Text(0, " consonants.^M^J");
    Text(0, "Contains ");  IntOut(0, VDC);  Text(0, " distinct vowels and ");
    IntOut(0, CDC);  Text(0, " consonants.^M^J");
    CrLf(0);
    ];
]
Output:
Forever XPL0 programming language.
Contains 10 total vowels and 19 consonants.
Contains 5 distinct vowels and 9 consonants.

Now is the time for all good men to come to the aid of their country.
Contains 22 total vowels and 31 consonants.
Contains 5 distinct vowels and 13 consonants.