Toolmingo
Guides6 min read

How to Count Words and Characters in Any Text

Learn how word and character counting works, when each metric matters, and how to count accurately in JavaScript, Python, and more — plus a free online word counter tool.

Whether you're hitting a tweet's character limit, targeting a 1,000-word blog post, or enforcing a database VARCHAR(255) constraint, counting words and characters is a deceptively simple task that has several edge cases worth understanding.

This guide explains exactly how counting works, when to use words vs. characters vs. bytes, and how to implement counting correctly in code.

Words vs. characters vs. bytes

Before counting, pick the right unit:

Unit Counts When to use
Words Space-separated tokens Blog length, readability, SEO targets
Characters Individual code points Twitter, SMS, form field limits
Bytes Encoded bytes in memory Database columns, file size, API payloads

A single emoji like 😀 is 1 character but 4 bytes in UTF-8. A Chinese character like 你 is 1 character but 3 bytes. Most user-facing limits (Twitter, Instagram, form fields) count characters, not bytes — but MySQL VARCHAR(255) historically counted bytes, which tripped up many developers.

How word counting works

The simplest definition of a word is any sequence of non-whitespace characters separated by whitespace. In code:

function countWords(text) {
  return text.trim() === '' ? 0 : text.trim().split(/\s+/).length;
}

The \s+ regex matches one or more whitespace characters (space, tab, newline), so multiple spaces between words don't inflate the count.

Edge cases:

  • Leading/trailing whitespace — always .trim() first
  • Multiple consecutive spaces — use \s+ not ' ' (a single space)
  • Hyphenated words — well-known counts as 1 word in most tools, 2 in some
  • Contractions — don't counts as 1 word
  • Numbers — 42 and 3.14 count as 1 word each
  • Empty string — should return 0, not 1

How character counting works

function countCharacters(text) {
  return text.length;
}

In JavaScript, String.prototype.length counts UTF-16 code units. Most characters are one code unit, but characters outside the Basic Multilingual Plane (emoji, some rare scripts) are two. For emoji-heavy content, use the spread operator or Array.from():

// Correct for emoji
function countCharactersCorrect(text) {
  return [...text].length;
}

// Examples
'hello'.length          // 5 ✓
'😀'.length             // 2 ✗ (UTF-16 surrogate pair)
[...'😀'].length        // 1 ✓

Twitter counts characters using Unicode code points, which aligns with [...text].length.

Counting with and without spaces

Some platforms (like academic word processors) report characters with and without spaces as two separate numbers. Implement both:

function textStats(text) {
  const withSpaces = [...text].length;
  const withoutSpaces = [...text.replace(/\s/g, '')].length;
  const words = text.trim() === '' ? 0 : text.trim().split(/\s+/).length;
  const lines = text === '' ? 0 : text.split('\n').length;
  const sentences = (text.match(/[.!?]+/g) || []).length;

  return { withSpaces, withoutSpaces, words, lines, sentences };
}

Counting in different languages

Python

def word_count(text: str) -> int:
    return len(text.split())

def char_count(text: str) -> int:
    return len(text)  # Python 3 counts Unicode code points

# Examples
word_count("Hello world")      # 2
word_count("  spaces  here  ") # 2 — split() handles multiple spaces
char_count("café")             # 4 — correct in Python 3
char_count("😀")               # 1 — correct in Python 3

Python 3's len() already counts Unicode code points correctly — no need for the spread-operator trick from JavaScript.

Go

import (
    "strings"
    "unicode/utf8"
)

func wordCount(s string) int {
    return len(strings.Fields(s))
}

func charCount(s string) int {
    return utf8.RuneCountInString(s)
}

// strings.Fields handles any whitespace, including tabs and newlines
// utf8.RuneCountInString counts code points (not bytes)

len(s) in Go counts bytes, not characters. Always use utf8.RuneCountInString() for character counts.

PHP

function wordCount(string $text): int {
    return str_word_count(trim($text));
}

function charCount(string $text): int {
    return mb_strlen($text, 'UTF-8');
}

PHP's strlen() counts bytes; mb_strlen() counts multibyte characters. Always use the mb_ variant for user-facing text.

Platform-specific limits

Knowing the limit is only half the job — you need to know what gets counted:

Platform Limit Counts
Twitter / X 280 Unicode code points (emoji = 2 regardless)
Instagram caption 2,200 Characters
TikTok description 2,200 Characters
LinkedIn post 3,000 Characters
SMS (GSM-7) 160 per message 7-bit characters
SMS (Unicode) 70 per message Unicode characters
Meta description ~155 Characters (Google truncates visually)
YouTube description 5,000 Characters
<input maxlength> developer-set UTF-16 code units

Twitter note: Twitter counts most characters as 1, but URLs always count as 23 characters regardless of actual length, and some emoji count as 2 (a platform-specific rule, not standard Unicode).

Reading time estimation

A common companion metric to word count is estimated reading time. The average adult reads 200–250 words per minute:

function readingTime(text) {
  const words = text.trim().split(/\s+/).length;
  const minutes = Math.ceil(words / 225);
  return minutes === 1 ? '1 min read' : `${minutes} min read`;
}

Adjust the divisor: technical content reads slower (~150 wpm), light blog posts faster (~250 wpm).

Practical use cases

Blog posts: Aim for 800–2,000 words for SEO-friendly articles. Under 300 words is considered "thin content" by search engines.

Academic papers: Word counts are often strict (2,500 ± 10%). Most word processors include footnotes and citations in the count — check the style guide.

Database columns: If your column is VARCHAR(255), enforce the limit client-side before inserting. Use byte-aware counting for non-ASCII content in databases with byte-length semantics.

Input validation: Always enforce limits server-side even if you show a counter client-side. Malicious users can bypass front-end limits.

// React controlled input with live counter
function TextInput({ maxLength = 280 }) {
  const [text, setText] = React.useState('');
  const chars = [...text].length;
  const remaining = maxLength - chars;

  return (
    <div>
      <textarea
        value={text}
        onChange={e => setText(e.target.value)}
        maxLength={maxLength}
      />
      <span style={{ color: remaining < 20 ? 'red' : 'inherit' }}>
        {remaining} characters remaining
      </span>
    </div>
  );
}

Count text instantly

Instead of writing the code yourself, paste any text into Toolmingo's Word Counter to instantly see word count, character count (with and without spaces), line count, sentence count, and estimated reading time — all in one place.

FAQ

Q: Why does my word processor show a different count than an online tool? Word processors differ in how they handle hyphenated words, contractions, footnotes, and headers. There's no single universal standard — the difference is usually ±1–3%.

Q: Does punctuation count as a character? Yes, every printable character including commas, periods, and quotes counts as a character. Whitespace also counts unless you select "without spaces."

Q: What's the difference between characters and bytes for database limits? In MySQL, VARCHAR(255) with utf8mb4 character set stores up to 255 characters (each up to 4 bytes). A column can contain up to 255 emoji even though each emoji is 4 bytes. In older configurations using utf8 (3 bytes max), emoji would be stored incorrectly — always use utf8mb4.

Q: Does a newline count as a character? A newline (\n) is a single character with value 10. It counts toward character counts. When counting "without spaces," newlines are usually excluded since they're whitespace.

Q: How do I count words in a file from the command line? Use wc on Unix/macOS/Linux:

wc -w filename.txt   # word count
wc -c filename.txt   # byte count
wc -m filename.txt   # character count (locale-aware)
wc -l filename.txt   # line count

On Windows PowerShell:

(Get-Content file.txt | Measure-Object -Word).Words
(Get-Content file.txt).Length   # line count

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools