Skip to content

Word & Character Counter — C++ source

Live word, character, sentence, and paragraph counts plus reading-time estimate as you type.

This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.

// word-counter — C++ port: word / character / sentence / paragraph counts + 200-wpm reading-time estimate.
// Display snippet: ports the counters from the TypeScript lib (src/lib/wordCount.ts); string_view
// counts bytes, so multi-byte UTF-8 diverges from the TS reference's UTF-16 code units.
#include <cctype>
#include <cstdio>
#include <string_view>

namespace word_counter {

// Words: runs of non-whitespace (ASCII subset of the JS /\s/). Blank input -> 0.
inline long count_words(std::string_view t) {
    long n = 0;
    bool in_word = false;
    for (char c : t) {
        if (std::isspace(static_cast<unsigned char>(c))) in_word = false;
        else if (!in_word) { in_word = true; ++n; }
    }
    return n;
}
// Total character count, whitespace included.
inline long count_chars(std::string_view t) { return static_cast<long>(t.size()); }
// Character count with every whitespace byte removed.
inline long count_chars_no_spaces(std::string_view t) {
    long n = 0;
    for (char c : t) if (!std::isspace(static_cast<unsigned char>(c))) ++n;
    return n;
}
// Sentences: maximal runs of non-terminators each closed by one or more of
// . ! ? — the TS regex /[^.!?]+[.!?]+/g as a single scan.
inline long count_sentences(std::string_view t) {
    long n = 0;
    bool body = false;
    for (char c : t) {
        if (c == '.' || c == '!' || c == '?') {
            if (body) { ++n; body = false; }
        } else {
            body = true;
        }
    }
    return n;
}
// Paragraphs: segments split by runs of 2+ newlines; blank segments don't
// count (the TS split(/\n{2,}/).filter(s => s.trim())).
inline long count_paragraphs(std::string_view t) {
    long n = 0, run = 0;
    bool blank = true;
    for (char c : t) {
        if (c == '\n') {
            if (++run == 2) {  // blank line closes the paragraph
                if (!blank) ++n;
                blank = true;
            }
            continue;
        }
        run = 0;
        if (!std::isspace(static_cast<unsigned char>(c))) blank = false;
    }
    return blank ? n : n + 1;
}
// Reading time at 200 wpm: 0 for empty, else >= 1 min; (w + 100) / 200 == Math.round(w / 200).
inline long reading_time_min(long words) {
    if (words <= 0) return 0;
    long m = (words + 100) / 200;
    return m < 1 ? 1 : m;
}
}  // namespace word_counter

int main() {
    using namespace word_counter;
    std::string_view text = "CosmoDev counts words. Live totals update as you type!\n\n"
                            "Second paragraph? Two sentences - each with words. Zero logins needed.";
    long w = count_words(text);
    std::printf("words:       %ld\n", w);                           // 20
    std::printf("chars:       %ld\n", count_chars(text));           // 126
    std::printf("no spaces:   %ld\n", count_chars_no_spaces(text)); // 106
    std::printf("sentences:   %ld\n", count_sentences(text));       // 5
    std::printf("paragraphs:  %ld\n", count_paragraphs(text));      // 2
    std::printf("reading min: %ld\n", reading_time_min(w));         // 1
    return 0;
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →