Skip to content

Character Counter

Detailed character frequency breakdown.

A character counter reports how many characters are in a string. The interesting question is what counts as one character. The tool above runs in your browser and reports several counts (characters with and without whitespace, words, lines, bytes, code points); this page explains why the counts can differ from each other and from what users expect.

Four definitions of “character”

DefinitionWhat it countsWhere it’s used
BytesRaw bytes of the encoded stringDatabase varchar limits in some systems, network protocol limits
Code unitsUTF-16 16-bit units (JavaScript string.length)JavaScript-native APIs
Code pointsUnicode characters (after combining surrogate pairs)Most APIs that say “character”
Grapheme clustersWhat a human perceives as one characterUser-facing counts (tweet limits, form labels)

For ASCII-only input, all four agree. For everything else, they can diverge.

Where they disagree

String:  "café"
Bytes (UTF-8):     5  (c=1, a=1, f=1, é=2)
UTF-16 units:      4  (each char fits in one unit)
Code points:       4
Grapheme clusters: 4
String:  "👨‍👩‍👧" (family emoji = man + ZWJ + woman + ZWJ + girl)
Bytes (UTF-8):     18
UTF-16 units:      8  (three surrogate pairs + two ZWJ)
Code points:       5  (M, ZWJ, W, ZWJ, G)
Grapheme clusters: 1  ← what users see
String:  "👋🏽" (waving hand with skin tone modifier)
Bytes (UTF-8):     8
UTF-16 units:      4
Code points:       2  (hand + skin tone)
Grapheme clusters: 1  ← what users see

When a user pastes a “single emoji” and the counter says 7, the counter is reporting code points, not grapheme clusters. The emoji is one perceived character but multiple code points.

What the tool above reports

  • Characters. Grapheme clusters — what a reader sees as one character — counted with the browser’s Intl.Segmenter. A thumbs-up with a skin tone is 1.
  • Characters (no spaces). The same, minus whitespace.
  • Words. Whitespace-delimited tokens.
  • Lines. Line-break-delimited segments (see below).
  • Bytes (UTF-8). Useful for database column sizing.
  • Code points and UTF-16 units — the numbers most programming languages report (len() in Python 3 counts code points; .length in JavaScript counts UTF-16 units).
  • Unique code points, spaces, letters, digits and the five most frequent characters.

Why the differences matter

  • Twitter / X tweet limits. Historically counted code points (with some characters weighted as 2). Updates have moved closer to grapheme clusters. The visible-character count drives the limit.
  • SMS message limits. GSM-7 encoding fits 160 7-bit characters; UCS-2 fits 70 16-bit code units; longer messages are split into segments. A tweet with one emoji silently switches encoding and halves the per-segment limit.
  • Database columns. A VARCHAR(50) in MySQL means 50 characters in utf8mb4 charset; BYTEA and some other types are byte-counted. A 50-byte limit fits 50 ASCII or only 12 of the 4-byte family-emoji clusters.
  • Form validation. Telling a user “max 280 characters” and rejecting their post because your code count differs from theirs is a usability bug. Use grapheme clusters for limits the user perceives.

Words and how they’re counted

Words are even messier than characters:

  • Whitespace tokenization. The simplest definition: split on whitespace. Works for English; fails for Chinese, Japanese, Thai (no spaces between words).
  • Word-boundary detection. Unicode defines word-boundary rules (UAX #29). Modern segmenters use these.
  • Hyphenation. Is “well-known” one word or two? The convention varies; whitespace splitters usually call it one.
  • Apostrophes. “Don’t” is one word. “Rock ‘n’ roll” is — depending on the splitter — one to four.

The tool above uses whitespace tokenization, which matches the conventional word-counter UX (Microsoft Word, Google Docs). For Unicode-aware segmentation, browser Intl.Segmenter is the right primitive.

Lines

A “line” is everything up to a line terminator. The tool above counts content lines: one\ntwo is two lines, and so is one\ntwo\n — a final newline ends the last line rather than starting an empty one.

Edge cases:

  • CRLF vs LF. Both terminate a line; the count is the same. The tool treats CRLF as a single line break.
  • Trailing newline. A file that ends with \n has the same line count as one without. That differs from wc -l, which counts newline characters: wc -l says 1 for one\ntwo.
  • Blank lines in the middle. They count — one\n\ntwo is three lines.

Common pitfalls

  • Using string.length in JavaScript as a character count. string.length returns UTF-16 code units. Surrogate-pair characters (most emoji) count as 2. Astral-plane Unicode (some Chinese, math symbols) counts as 2. For human-perceived counts, use Intl.Segmenter.
  • Mismatched counters between client and server. A browser counting grapheme clusters and a Python server counting bytes will disagree on long inputs. Decide which definition is canonical, document it, and align both ends.
  • Counting whitespace as content. “1,500 characters with spaces” looks longer than “1,500 characters without spaces” — same content, different number. Most word-count UIs report both.

For other text utilities, see the word counter, line counter, and text case converter.