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). C strings are
bytes, so counts are byte counts — multi-byte UTF-8 diverges from the TS reference's UTF-16 units. */
#include <ctype.h>
#include <stdio.h>
#include <string.h>
/* Words: runs of non-whitespace (ASCII subset of the JS /\s/). Blank input -> 0. */
static long count_words(const char *t) {
long n = 0;
int in_word = 0;
for (; *t; t++) {
if (isspace((unsigned char)*t)) in_word = 0;
else if (!in_word) { in_word = 1; n++; }
}
return n;
}
/* Total character count, whitespace included. */
static long count_chars(const char *t) { return (long)strlen(t); }
/* Character count with every whitespace byte removed. */
static long count_chars_no_spaces(const char *t) {
long n = 0;
for (; *t; t++)
if (!isspace((unsigned char)*t)) n++;
return n;
}
/* Sentences: maximal runs of non-terminators each closed by one or more of
. ! ? — the TS regex /[^.!?]+[.!?]+/g as a single scan. */
static long count_sentences(const char *t) {
long n = 0;
int body = 0;
for (; *t; t++) {
if (*t == '.' || *t == '!' || *t == '?') {
if (body) { n++; body = 0; }
} else {
body = 1;
}
}
return n;
}
/* Paragraphs: segments split by runs of 2+ newlines; blank segments don't
count (the TS split(/\n{2,}/).filter(s => s.trim())). */
static long count_paragraphs(const char *t) {
long n = 0, run = 0;
int blank = 1;
for (; *t; t++) {
if (*t == '\n') {
if (++run == 2) { /* blank line closes the paragraph */
if (!blank) n++;
blank = 1;
}
continue;
}
run = 0;
if (!isspace((unsigned char)*t)) blank = 0;
}
return blank ? n : n + 1;
}
/* Reading time at 200 wpm: 0 for empty, else >= 1 min; (w + 100) / 200 == Math.round(w / 200). */
static long reading_time_min(long words) {
if (words <= 0) return 0;
long m = (words + 100) / 200;
return m < 1 ? 1 : m;
}
int main(void) {
const char *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);
printf("words: %ld\n", w); /* 20 */
printf("chars: %ld\n", count_chars(text)); /* 126 */
printf("no spaces: %ld\n", count_chars_no_spaces(text)); /* 106 */
printf("sentences: %ld\n", count_sentences(text)); /* 5 */
printf("paragraphs: %ld\n", count_paragraphs(text)); /* 2 */
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 →