I spent 20 minutes manually fixing a blog post that had been drafted in Microsoft Word and pasted directly into a CMS. The βsmart quotesβ broke the template. The en-dashes looked wrong in the browser. There were non-breaking spaces that pushed layout elements out of place. Every one of these is a different character that the visual editor hid. A 30-second text cleaning pass before pasting would have saved those 20 minutes.
Count words, clean text, convert case, locally.
Text tools that run in your browser. Your drafts never leave your device.
Open Word Counter βWord Count and Reading Time
Word count & reading time
Words, characters with and without spaces, sentences, plus reading time at 200-240 wpm.
Case conversion
Upper, lower, title, sentence, camelCase, kebab-case, and snake_case.
Text cleaning
Strip non-breaking spaces, zero-width spaces, smart quotes, and em dashes from pasted text.
Markdown to HTML
Convert Markdown to HTML with marked or markdown-it for CMSes and email.
A word counter should give you more than a single number. The useful metrics for writing are:
- Word count: split on whitespace, handle multi-word hyphenated terms correctly
- Character count (with spaces): relevant for character-limited platforms (Twitter, meta descriptions)
- Character count (without spaces): relevant for SMS (160 characters per SMS segment)
- Reading time: based on 200β240 words per minute (typical adult reading speed)
- Speaking time: based on 130 words per minute (typical speech rate)
- Sentence count and average sentence length: readability indicators
1// Text analysis in JavaScript2function analyzeText(text: string) {3 // Normalise whitespace4 const cleaned = text.trim().replace(/s+/g, ' ');5Β 6 const words = cleaned.split(/s+/).filter(w => w.length > 0);7 const sentences = cleaned.split(/[.!?]+/).filter(s => s.trim().length > 0);8 const chars = cleaned.length;9 const charsNoSpaces = cleaned.replace(/s/g, '').length;10Β 11 return {12 wordCount: words.length,13 charCount: chars,14 charCountNoSpaces: charsNoSpaces,15 sentenceCount: sentences.length,16 avgWordsPerSentence: Math.round(words.length / sentences.length),17 readingTime: Math.ceil(words.length / 220), // minutes at 220 wpm18 speakingTime: Math.ceil(words.length / 130), // minutes at 130 wpm19 };20}Case Conversion
The cases that actually come up in real work:
1const text = "the quick BROWN fox jumps over the lazy dog";2Β 3// Common case conversions4const uppercase = text.toUpperCase();5// β "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG"6Β 7const lowercase = text.toLowerCase();8// β "the quick brown fox jumps over the lazy dog"9Β 10const titleCase = text.replace(/w/g, c => c.toUpperCase());11// β "The Quick BROWN Fox Jumps Over The Lazy Dog"12// (Note: doesn't fix existing uppercase β see sentenceCase)13Β 14const sentenceCase = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();15// β "The quick brown fox jumps over the lazy dog"16Β 17// camelCase β for variable names18const camelCase = text19 .split(/s+/)20 .map((word, i) => i === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())21 .join('');22// β "theQuickBrownFoxJumpsOverTheLazyDog"23Β 24// kebab-case β for CSS classes, URL slugs25const kebabCase = text.toLowerCase().replace(/s+/g, '-');26// β "the-quick-brown-fox-jumps-over-the-lazy-dog"27Β 28// snake_case β for database columns, Python variables29const snakeCase = text.toLowerCase().replace(/s+/g, '_');30// β "the_quick_brown_fox_jumps_over_the_lazy_dog"Text Cleaning: Removing Hidden Junk
This is the unglamorous category of text tools that saves the most time in practice. When you copy text from a browser, PDF, or Word document, you often get invisible characters:
1// Common hidden characters that break layouts and templates2// (Use charCodeAt() to detect them in JavaScript)3Β 4// Non-breaking space (U+00A0) β looks like a space, breaks word-wrap differently5'Β '.charCodeAt(0); // β 160 (not 32 like a regular space)6Β 7// Zero-width space (U+200B) β invisible, breaks string matching8'β'.charCodeAt(0); // β 82039Β 10// Smart quotes β look like quotes, break code and JSON11'β' // Left single quote '12'β' // Right single quote '13'β' // Left double quote "14'β' // Right double quote "15Β 16// Em dash (U+2014) vs hyphen (U+002D) β breaks regex patterns17'β' // Em dash β18'-' // Hyphen -19Β 20// Clean all of these in one pass:21function cleanText(text: string): string {22 return text23 .replace(/Β /g, ' ') // NBSP β space24 .replace(/β/g, '') // Zero-width space β remove25 .replace(/[ββ]/g, "'") // Smart quotes β straight26 .replace(/[ββ]/g, '"') // Smart double quotes β straight27 .replace(/β/g, '--') // Em dash β double hyphen28 .replace(/
29/g, '30') // Windows line endings β Unix31 .replace(/
/g, '32') // Old Mac line endings β Unix33 .replace(/34{3,}/g, '35Β 36') // Multiple blank lines β max 137 .trim();38}Markdown to HTML Conversion
For writers who work in Markdown but need HTML output (for CMSes, email clients, or documentation systems), a local markdown converter is useful. The two most common JavaScript Markdown parsers:
- marked: Fast, small (10KB), supports GitHub Flavored Markdown (GFM)
- markdown-it: More extensible, good plugin ecosystem, supports tables and footnotes
1import { marked } from 'marked';2Β 3const markdown = `4# Article Title5Β 6This is a **bold** statement with *italic* emphasis.7Β 8- Item one9- Item two10- Item three11Β 12\`\`\`javascript13const x = 42;14\`\`\`15`;16Β 17// Convert to HTML18const html = marked.parse(markdown);19// β <h1>Article Title</h1><p>This is a <strong>bold</strong>...</p>20Β 21// For safe rendering in browser (sanitise to prevent XSS)22import DOMPurify from 'dompurify';23document.getElementById('output').innerHTML = DOMPurify.sanitize(html);For developers working with structured data rather than prose, our JSON data tools guide covers formatting, querying, and transforming JSON, the structured text equivalent of these prose utilities.
Word count, case conversion, and text cleaning: in your browser.
No upload. Your text stays local.
Open Word Counter β