RosettaCodeData/Task/Word-frequency/ALGOL-68/word-frequency.alg
2023-07-01 13:44:08 -04:00

125 lines
5.1 KiB
Text

# find the n most common words in a file #
# use the associative array in the Associate array/iteration task #
# but with integer values #
PR read "aArrayBase.a68" PR
MODE AAKEY = STRING;
MODE AAVALUE = INT;
AAVALUE init element value = 0;
# returns text converted to upper case #
OP TOUPPER = ( STRING text )STRING:
BEGIN
STRING result := text;
FOR ch pos FROM LWB result TO UPB result DO
IF is lower( result[ ch pos ] ) THEN result[ ch pos ] := to upper( result[ ch pos ] ) FI
OD;
result
END # TOUPPER # ;
# returns text converted to an INT or -1 if text is not a number #
OP TOINT = ( STRING text )INT:
BEGIN
INT result := 0;
BOOL is numeric := TRUE;
FOR ch pos FROM UPB text BY -1 TO LWB text WHILE is numeric DO
CHAR c = text[ ch pos ];
is numeric := is numeric AND c >= "0" AND c <= "9";
IF is numeric THEN ( result *:= 10 ) +:= ABS c - ABS "0" FI
OD;
IF is numeric THEN result ELSE -1 FI
END # TOINT # ;
# returns TRUE if c is a letter, FALSE otherwise #
OP ISLETTER = ( CHAR c )BOOL:
IF ( c >= "a" AND c <= "z" )
OR ( c >= "A" AND c <= "Z" )
THEN TRUE
ELSE char in string( c, NIL, "ÇåçêëÆôöÿÖØáóÔ" )
FI # ISLETER # ;
# get the file name and number of words from then commmand line #
STRING file name := "pg-les-misrables.txt";
INT number of words := 10;
FOR arg pos TO argc - 1 DO
STRING arg upper = TOUPPER argv( arg pos );
IF arg upper = "FILE" THEN
file name := argv( arg pos + 1 )
ELIF arg upper = "NUMBER" THEN
number of words := TOINT argv( arg pos + 1 )
FI
OD;
IF FILE input file;
open( input file, file name, stand in channel ) /= 0
THEN
# failed to open the file #
print( ( "Unable to open """ + file name + """", newline ) )
ELSE
# file opened OK #
print( ( "Processing: ", file name, newline ) );
BOOL at eof := FALSE;
BOOL at eol := FALSE;
# set the EOF handler for the file #
on logical file end( input file, ( REF FILE f )BOOL:
BEGIN
# note that we reached EOF on the #
# latest read #
at eof := TRUE;
# return TRUE so processing can continue #
TRUE
END
);
# set the end-of-line handler for the file so get word can see line boundaries #
on line end( input file
, ( REF FILE f )BOOL:
BEGIN
# note we reached end-of-line #
at eol := TRUE;
# return FALSE to use the default eol handling #
# i.e. just get the next charactefr #
FALSE
END
);
# get the words from the file and store the counts in an associative array #
REF AARRAY words := INIT LOC AARRAY;
INT word count := 0;
CHAR c := " ";
WHILE get( input file, ( c ) );
NOT at eof
DO
WHILE NOT ISLETTER c AND NOT at eof DO get( input file, ( c ) ) OD;
STRING word := "";
at eol := FALSE;
WHILE ISLETTER c AND NOT at eol AND NOT at eof DO word +:= c; get( input file, ( c ) ) OD;
word count +:= 1;
words // TOUPPER word +:= 1
OD;
close( input file );
print( ( file name, " contains ", whole( word count, 0 ), " words", newline ) );
# find the most used words #
[ number of words ]STRING top words;
[ number of words ]INT top counts;
FOR i TO number of words DO top words[ i ] := ""; top counts[ i ] := 0 OD;
REF AAELEMENT w := FIRST words;
WHILE w ISNT nil element DO
INT count = value OF w;
STRING word = key OF w;
BOOL found := FALSE;
FOR i TO number of words WHILE NOT found DO
IF count > top counts[ i ] THEN
# found a word that is used nore than a current #
# most used word #
found := TRUE;
# move the other words down one place #
FOR move pos FROM number of words BY - 1 TO i + 1 DO
top counts[ move pos ] := top counts[ move pos - 1 ];
top words [ move pos ] := top words [ move pos - 1 ]
OD;
# install the new word #
top counts[ i ] := count;
top words [ i ] := word
FI
OD;
w := NEXT words
OD;
print( ( whole( number of words, 0 ), " most used words:", newline ) );
print( ( " count word", newline ) );
FOR i TO number of words DO
print( ( whole( top counts[ i ], -6 ), ": ", top words[ i ], newline ) )
OD
FI