Task: Word frequency

C: #include <stdbool.h>
#include <stdio.h>
#include <glib.h>

typedef struct word_count_tag {
    const char* word;
    size_t count;
} word_count;

int compare_word_count(const void* p1, const void* p2) {
    const word_count* w1 = p1;
    const word_count* w2 = p2;
    if (w1->count > w2->count)
        return -1;
    if (w1->count < w2->count)
        return 1;
    return 0;
}

bool get_top_words(const char* filename, size_t count) {
    GError* error = NULL;
    GMappedFile* mapped_file = g_mapped_file_new(filename, FALSE, &error);
    if (mapped_file == NULL) {
        fprintf(stderr, "%s\n", error->message);
        g_error_free(error);
        return false;
    }
    const char* text = g_mapped_file_get_contents(mapped_file);
    if (text == NULL) {
        fprintf(stderr, "File %s is empty\n", filename);
        g_mapped_file_unref(mapped_file);
        return false;
    }
    gsize file_size = g_mapped_file_get_length(mapped_file);
    
    GHashTable* ht = g_hash_table_new_full(g_str_hash, g_str_equal,
                                           g_free, g_free);
    GRegex* regex = g_regex_new("\\w+", 0, 0, NULL);
    GMatchInfo* match_info;
    g_regex_match_full(regex, text, file_size, 0, 0, &match_info, NULL);
    while (g_match_info_matches(match_info)) {
        char* word = g_match_info_fetch(match_info, 0);
        char* lower = g_utf8_strdown(word, -1);
        g_free(word);
        size_t* count = g_hash_table_lookup(ht, lower);
        if (count != NULL) {
            ++*count;
            g_free(lower);
        } else {
            count = g_new(size_t, 1);
            *count = 1;
            g_hash_table_insert(ht, lower, count);
        }
        g_match_info_next(match_info, NULL);
    }
    g_match_info_free(match_info);
    g_regex_unref(regex);
    g_mapped_file_unref(mapped_file);

    
    size_t size = g_hash_table_size(ht);
    word_count* words = g_new(word_count, size);
    GHashTableIter iter;
    gpointer key, value;
    g_hash_table_iter_init(&iter, ht);
    for (size_t i = 0; g_hash_table_iter_next(&iter, &key, &value); ++i) {
        words[i].word = key;
        words[i].count = *(size_t*)value;
    }
    qsort(words, size, sizeof(word_count), compare_word_count);

    
    if (count > size)
        count = size;
    printf("Top %lu words\n", count);
    printf("Rank\tCount\tWord\n");
    for (size_t i = 0; i < count; ++i)
        printf("%lu\t%lu\t%s\n", i + 1, words[i].count, words[i].word);
    g_free(words);
    g_hash_table_destroy(ht);
    return true;
}

int main(int argc, char** argv) {
    if (argc != 2) {
        fprintf(stderr, "usage: %s file\n", argv[0]);
        return EXIT_FAILURE;
    }
    if (!get_top_words(argv[1], 10))
        return EXIT_FAILURE;
    return EXIT_SUCCESS;
}








VB: Option Explicit

Private Const PATHFILE As String = "C:\HOME\VBA\ROSETTA"

Sub Main()
Dim arr
Dim Dict As Object
Dim Book As String, temp As String
Dim T#
T = Timer
   Book = ExtractTxt(PATHFILE & "\les miserables.txt")
   temp = RemovePunctuation(Book)
   temp = UCase(temp)
   arr = Split(temp, " ")
   Set Dict = CreateObject("Scripting.Dictionary")
   FillDictionary Dict, arr
   Erase arr
   SortDictByFreq Dict, arr
   DisplayTheTopMostUsedWords arr, 10

Debug.Print "Words different in this book : " & Dict.Count
Debug.Print "-------------------------"
Debug.Print ""
Debug.Print "Optionally : "
Debug.Print "Frequency of the word MISERABLE : " & DisplayFrequencyOf("MISERABLE", Dict)
Debug.Print "Frequency of the word DISASTER : " & DisplayFrequencyOf("DISASTER", Dict)
Debug.Print "Frequency of the word ROSETTA_CODE : " & DisplayFrequencyOf("ROSETTA_CODE", Dict)
Debug.Print "-------------------------"
Debug.Print "Execution Time : " & Format(Timer - T, "0.000") & " sec."
End Sub

Private Function ExtractTxt(strFile As String) As String

Dim i As Integer
   i = FreeFile
   Open strFile For Input As #i
       ExtractTxt = Input(LOF(1), #i)
   Close #i
End Function

Private Function RemovePunctuation(strBook As String) As String
Dim T, i As Integer, temp As String
Const PUNCT As String = """,;:!?."
   T = Split(StrConv(PUNCT, vbUnicode), Chr(0))
   temp = strBook
   For i = LBound(T) To UBound(T) - 1
      temp = Replace(temp, T(i), " ")
   Next
   temp = Replace(temp, "--", " ")
   temp = Replace(temp, "...", " ")
   temp = Replace(temp, vbCrLf, " ")
   RemovePunctuation = Replace(temp, "  ", " ")
End Function

Private Sub FillDictionary(d As Object, a As Variant)
Dim L As Long
   For L = LBound(a) To UBound(a)
      If a(L) <> "" Then _
         d(a(L)) = d(a(L)) + 1
   Next
End Sub

Private Sub SortDictByFreq(d As Object, myArr As Variant)
Dim K
Dim L As Long
   ReDim myArr(1 To d.Count, 1 To 2)
   For Each K In d.keys
      L = L + 1
      myArr(L, 1) = K
      myArr(L, 2) = CLng(d(K))
   Next
   SortArray myArr, LBound(myArr), UBound(myArr), 2
End Sub

Private Sub SortArray(a, Le As Long, Ri As Long, Col As Long)
Dim ref As Long, L As Long, r As Long, temp As Variant
   ref = a((Le + Ri) \ 2, Col)
   L = Le
   r = Ri
   Do
         Do While a(L, Col) < ref
            L = L + 1
         Loop
         Do While ref < a(r, Col)
            r = r - 1
         Loop
         If L <= r Then
            temp = a(L, 1)
            a(L, 1) = a(r, 1)
            a(r, 1) = temp
            temp = a(L, 2)
            a(L, 2) = a(r, 2)
            a(r, 2) = temp
            L = L + 1
            r = r - 1
         End If
   Loop While L <= r
   If L < Ri Then SortArray a, L, Ri, Col
   If Le < r Then SortArray a, Le, r, Col
End Sub

Private Sub DisplayTheTopMostUsedWords(arr As Variant, Nb As Long)
Dim L As Long, i As Integer
   i = 1
   Debug.Print "Rank Word    Frequency"
   Debug.Print "==== ======= ========="
   For L = UBound(arr) To UBound(arr) - Nb + 1 Step -1
      Debug.Print Left(CStr(i) & "    ", 5) & Left(arr(L, 1) & "       ", 8) & " " & Format(arr(L, 2), "0 000")
      i = i + 1
   Next
End Sub

Private Function DisplayFrequencyOf(Word As String, d As Object) As Long
   If d.Exists(Word) Then _
      DisplayFrequencyOf = d(Word)
End Function