Task: XXXX redacted

C: #include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

typedef enum {
    whole_word = 1,
    overkill = 2,
    case_insensitive = 4
} redact_options;

bool is_word_char(char ch) {
    return ch == '-' || isalpha((unsigned char)ch);
}


void redact(char* text, const char* target, redact_options options) {
    size_t target_length = strlen(target);
    if (target_length == 0)
        return;
    char* start = text;
    char* end = text + strlen(text);
    while (start < end) {
        
        
        char* str = (options & case_insensitive) ? strcasestr(start, target)
                        : strstr(start, target);
        if (str == NULL)
            break;
        char* word_start = str;
        char* word_end = str + target_length;
        if (options & (overkill | whole_word)) {
            while (word_start > start && is_word_char(*(word_start - 1)))
                --word_start;
            while (word_end < end && is_word_char(*word_end))
                ++word_end;
        }
        if (!(options & whole_word) ||
            (word_start == str && word_end == str + target_length))
            memset(word_start, 'X', word_end - word_start);
        start = word_end;
    }
}

void do_basic_test(const char* target, redact_options options) {
    char text[] = "Tom? Toms bottom tomato is in his stomach while playing the "
        "\"Tom-tom\" brand tom-toms. That's so tom.";
    redact(text, target, options);
    printf("[%c|%c|%c]: %s\n", (options & whole_word) ? 'w' : 'p',
           (options & case_insensitive) ? 'i' : 's',
           (options & overkill) ? 'o' : 'n', text);
}

void do_basic_tests(const char* target) {
    printf("Redact '%s':\n", target);
    do_basic_test(target, whole_word);
    do_basic_test(target, whole_word | case_insensitive);
    do_basic_test(target, 0);
    do_basic_test(target, case_insensitive);
    do_basic_test(target, overkill);
    do_basic_test(target, case_insensitive | overkill);
}

int main() {
    do_basic_tests("Tom");
    printf("\n");
    do_basic_tests("tom");
    return 0;
}




Go: package main

import (
    "fmt"
    "github.com/rivo/uniseg"
    "log"
    "regexp"
    "strings"
)

func join(words, seps []string) string {
    lw := len(words)
    ls := len(seps)
    if lw != ls+1 {
        log.Fatal("mismatch between number of words and separators")
    }
    var sb strings.Builder
    for i := 0; i < ls; i++ {
        sb.WriteString(words[i])
        sb.WriteString(seps[i])
    }
    sb.WriteString(words[lw-1])
    return sb.String()
}

func redact(text, word, opts string) {
    var partial, overkill bool
    exp := word
    if strings.IndexByte(opts, 'p') >= 0 {
        partial = true
    }
    if strings.IndexByte(opts, 'o') >= 0 {
        overkill = true
    }
    if strings.IndexByte(opts, 'i') >= 0 {
        exp = `(?i)` + exp
    }
    rgx := regexp.MustCompile(`[\s!-&(-,./:-@[-^{-~]+`) 
    seps := rgx.FindAllString(text, -1)
    words := rgx.Split(text, -1)
    rgx2 := regexp.MustCompile(exp)
    for i, w := range words {
        match := rgx2.FindString(w)
        
        if match == "" || strings.Index(w, match+"\u200d") >= 0 ||
            strings.Index(w, "\u200d"+match) >= 0 {
            continue
        }
        switch {
        case overkill:
            words[i] = strings.Repeat("X", uniseg.GraphemeClusterCount(w))
        case !partial:
            if words[i] == match {
                words[i] = strings.Repeat("X", uniseg.GraphemeClusterCount(w))
            }
        case partial:
            repl := strings.Repeat("X", uniseg.GraphemeClusterCount(word))
            words[i] = rgx2.ReplaceAllLiteralString(w, repl)
        }
    }
    fmt.Printf("%s %s\n\n", opts, join(words, seps))
}

func printResults(text string, allOpts, allWords []string) {
    fmt.Printf("Text: %s\n\n", text)
    for _, word := range allWords {
        fmt.Printf("Redact '%s':\n", word)
        for _, opts := range allOpts {
            redact(text, word, opts)
        }
    }
    fmt.Println()
}

func main() {
    text := `Tom? Toms bottom tomato is in his stomach while playing the "Tom-tom" brand tom-toms. That's so tom.
'Tis very tomish, don't you think?`
    allOpts := []string{"[w|s|n]", "[w|i|n]", "[p|s|n]", "[p|i|n]", "[p|s|o]", "[p|i|o]"}
    allWords := []string{"Tom", "tom", "t"}
    printResults(text, allOpts, allWords)

    text = "🧑 👨 🧔 👨‍👩‍👦"
    allOpts = []string{"[w]"}
    allWords = []string{"👨", "👨‍👩‍👦"}
    printResults(text, allOpts, allWords)

    text = "Argentina🧑🇦🇹  France👨🇫🇷  Germany🧔🇩🇪  Netherlands👨‍👩‍👦🇳🇱"
    allOpts = []string{"[p]", "[p|o]"}
    printResults(text, allOpts, allWords)
}