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
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
// Text analysis in JavaScript
function analyzeText(text: string) {
// Normalise whitespace
const cleaned = text.trim().replace(/s+/g, ' ');
const words = cleaned.split(/s+/).filter(w => w.length > 0);
const sentences = cleaned.split(/[.!?]+/).filter(s => s.trim().length > 0);
const chars = cleaned.length;
const charsNoSpaces = cleaned.replace(/s/g, '').length;
return {
wordCount: words.length,
charCount: chars,
charCountNoSpaces: charsNoSpaces,
sentenceCount: sentences.length,
avgWordsPerSentence: Math.round(words.length / sentences.length),
readingTime: Math.ceil(words.length / 220), // minutes at 220 wpm
speakingTime: Math.ceil(words.length / 130), // minutes at 130 wpm
};
}Case Conversion
The cases that actually come up in real work:
const text = "the quick BROWN fox jumps over the lazy dog";
// Common case conversions
const uppercase = text.toUpperCase();
// β "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG"
const lowercase = text.toLowerCase();
// β "the quick brown fox jumps over the lazy dog"
const titleCase = text.replace(/w/g, c => c.toUpperCase());
// β "The Quick BROWN Fox Jumps Over The Lazy Dog"
// (Note: doesn't fix existing uppercase β see sentenceCase)
const sentenceCase = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
// β "The quick brown fox jumps over the lazy dog"
// camelCase β for variable names
const camelCase = text
.split(/s+/)
.map((word, i) => i === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join('');
// β "theQuickBrownFoxJumpsOverTheLazyDog"
// kebab-case β for CSS classes, URL slugs
const kebabCase = text.toLowerCase().replace(/s+/g, '-');
// β "the-quick-brown-fox-jumps-over-the-lazy-dog"
// snake_case β for database columns, Python variables
const snakeCase = text.toLowerCase().replace(/s+/g, '_');
// β "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:
// Common hidden characters that break layouts and templates
// (Use charCodeAt() to detect them in JavaScript)
// Non-breaking space (U+00A0) β looks like a space, breaks word-wrap differently
'Β '.charCodeAt(0); // β 160 (not 32 like a regular space)
// Zero-width space (U+200B) β invisible, breaks string matching
'β'.charCodeAt(0); // β 8203
// Smart quotes β look like quotes, break code and JSON
'β' // Left single quote '
'β' // Right single quote '
'β' // Left double quote "
'β' // Right double quote "
// Em dash (U+2014) vs hyphen (U+002D) β breaks regex patterns
'β' // Em dash β
'-' // Hyphen -
// Clean all of these in one pass:
function cleanText(text: string): string {
return text
.replace(/Β /g, ' ') // NBSP β space
.replace(/β/g, '') // Zero-width space β remove
.replace(/[ββ]/g, "'") // Smart quotes β straight
.replace(/[ββ]/g, '"') // Smart double quotes β straight
.replace(/β/g, '--') // Em dash β double hyphen
.replace(/
/g, '
') // Windows line endings β Unix
.replace(/
/g, '
') // Old Mac line endings β Unix
.replace(/
{3,}/g, '
') // Multiple blank lines β max 1
.trim();
}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
import { marked } from 'marked';
const markdown = `
# Article Title
This is a **bold** statement with *italic* emphasis.
- Item one
- Item two
- Item three
\`\`\`javascript
const x = 42;
\`\`\`
`;
// Convert to HTML
const html = marked.parse(markdown);
// β <h1>Article Title</h1><p>This is a <strong>bold</strong>...</p>
// For safe rendering in browser (sanitise to prevent XSS)
import DOMPurify from 'dompurify';
document.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 β