program wordfreq;
uses
SysUtils, Classes, Windows,
simpleHash in 'simpleHash.pas';
const
cWhiteSpace = [#0..#255]-['a'..'z','A'..'Z'];
BUF_SIZE = 4096;
var handle: THandle;
buf: array[1..BUF_SIZE+1] of char;
s,w: string;
words: TStringHash;
forSort: TList;
numRead,i,wStart: cardinal;
p: PHashEntry;
procedure addWord(const s: string);
var w: string; p: PHashEntry;
begin
w:=lowercase(s);
p:=words.get(w);
if p<>nil then
inc(p^.Value)
else
words.add(w,1);
end;
function sortFunc(Item1, Item2: Pointer): Integer;
begin
with PHashEntry(Item1)^ do begin
if Value<PHashEntry(Item2)^.Value then
result:=1
else if Value>PHashEntry(Item2)^.Value then
result:=-1
else begin // values equal
if Key=PHashEntry(Item2)^.Key then
result:=0
else if Key<PHashEntry(Item2)^.Key then
result:=1
else
result:=-1;
end;
end;
end;
begin
handle:=GetStdHandle(STD_INPUT_HANDLE);
words:=TStringHash.Create;
s:='';
buf[BUF_SIZE+1]:=#0;
numRead:=fileRead(handle,buf,BUF_SIZE);
while numRead>0 do begin
i:=1;
if (s<>'')and(buf[1] in cWhiteSpace) then begin
addWord(s); s:='';
end;
repeat
while (buf[i] in cWhiteSpace)and(i<=numRead) do
inc(i);
if i>numRead then
break; // repeat
wStart:=i;
repeat
inc(i);
until (buf[i] in cWhiteSpace);
setString(w,PChar(addr(buf[wStart])),i-wStart);
if s<>'' then begin
w:=s+w; s:='';
end;
if i<=numRead then
addWord(w)
else // word exceeding buffer
s:=w;
until (i>numRead);
numRead:=fileRead(handle,buf,BUF_SIZE);
end;
if (s<>'') then
addWord(s);
forSort:=TList.Create;
forSort.Capacity:=words.Count;
p:=words.getFirst;
while p<>nil do begin
forSort.Add(p);
p:=words.getNext;
end;
forSort.Sort(sortFunc);
for i:=0 to forSort.Count-1 do begin
p:=PHashEntry(forSort.Items[i]);
write(format('%7d'#9'%s'#13#10,[p^.Value,p^.Key]));
end;
words.Free; forSort.Free;
end.