Remove Invisible Characters from Word and Google Docs
For a spreadsheet column use the Excel cell cleaner. For code and payloads use the JSON cleaner. To find the difference between two strings, use compare texts.
Why the counts are on the page
When you clean a document you are about to submit, the worry is not whether it removed something — it is whether it removed something you wanted. So this page reports the word count and the character count before and after.
Removing invisible characters should not change the word count, because none of them are
word characters — with one exception that is worth knowing before you trust the number.
U+FEFF is the only invisible character JavaScript treats as whitespace, so
deleting it joins the two words sitting on either side of it and the count genuinely drops.
That is the one case where a lower number is expected rather than alarming. If the count
moves for any other reason, something is wrong and you should not use the result. That is the
whole point of showing it.
The one invisible character that makes text wider
Everything this page removes is invisible, but not all of it is invisible in the same way. Most of it takes up no room at all. U+3000 IDEOGRAPHIC SPACE works the other way round: measured in Chromium at a 16 px system font it advances 16.00 px, a full em, against 4.73 px for an ordinary space. One of them is worth about three and a half normal spaces, and it still puts no ink on the page.
| Character | Advance width at 16 px |
|---|---|
Ordinary space U+0020 | 4.73 px |
No-break space U+00A0 | 4.73 px |
Thin space U+2009 | 3.20 px |
Narrow no-break space U+202F | 2.38 px |
Medium mathematical space U+205F | 3.56 px |
Ideographic space U+3000 | 16.00 px |
| Capital letter A, for scale | 11.27 px |
That width is the character’s purpose: it is a space the size of one full-width character cell. It reaches a document two ways. An East-Asian input method produces it from the space bar, so it arrives without anyone deciding to type it. It is also typed on purpose instead of a tab, because it is exactly one cell wide and therefore looks like a reliable way to indent a line — a habit that shows up in documents with strict formatting rules, where the fix is reformatting rather than cleaning.
Once it is in the text it behaves like a space and not like the other invisible characters.
Put a 15-word sentence in a 420 px box: with ordinary spaces it lays out as
3 lines, with U+3000 between the words also 3 lines, and
with U+00A0 between them it is 1 line that runs off the edge
and never breaks. Delete the separators outright instead of replacing them and you get the
same result as the no-break space: one unbreakable line. So the normal advice holds here
— swap it for an ordinary space, do not remove it.
Four tools, four answers to “how many words”
Take five words joined by four copies of one separator, and ask everything on the machine how many words that is. A plain space gives five everywhere. Nothing else does.
| Separator | This page’s counter | Unicode word segmentation | wc -w, UTF-8 locale | awk fields | diff -w ignores it |
|---|---|---|---|---|---|
Ordinary space U+0020 | 5 | 5 | 5 | 5 | baseline |
No-break space U+00A0 | 5 | 5 | 5 | 1 | no |
Thin space U+2009 | 5 | 5 | 5 | 1 | yes |
Narrow no-break space U+202F | 5 | 1 | 5 | 1 | no |
Medium mathematical space U+205F | 5 | 5 | 5 | 1 | yes |
Ideographic space U+3000 | 5 | 5 | 5 | 1 | yes |
Zero width space U+200B | 1 | 5 | 1 | 1 | no |
Zero width no-break space U+FEFF | 5 | 1 | 1 | 1 | no |
Line separator U+2028 | 5 | 5 | 5 | 1 | yes |
Soft hyphen U+00AD | 1 | 1 | 1 | 1 | no |
The first two columns are both this browser, asked in two different ways. The counter above
splits on whitespace; Unicode word segmentation follows the word boundary rules instead, and
the two disagree in both directions. U+202F and U+FEFF are
boundaries for one and not the other. U+200B is the reverse: five words to the
segmentation rules, one word to the counter. “The word count did not move” is
therefore a statement about one particular counter, not about the text.
That matters because of what the cleaner actually does. It removes
U+FEFF with every option switched off, and since JavaScript counts
U+FEFF as whitespace, five words joined by it are five words before cleaning and
one word afterwards. The counter on this page will show
5 → 1 and raise its warning, and it is right to: nothing you could see was
lost, but alpha beta gamma delta epsilon has become
alphabetagammadeltaepsilon. If a word count is going to be checked downstream,
normalise instead of deleting.
The shell is worse. wc -w counts a no-break space as a word separator in a
UTF-8 locale and not in the C locale — two words for a + U+00A0 + b
under one, one word under the other — and in that same UTF-8 locale
awk still reports a single field. The two disagree because
wc carries its own list of non-breaking spaces rather than relying on the C
library’s wide-character whitespace test, which by design does not count a no-break
space as a space. Several people have run into this while writing a word counter and come
away with the same conclusion: the character class is locale-dependent, and it is not the
same class the other utilities use.
diff -w is a third answer. It ignores U+3000,
U+2009, U+205F and U+2028 but not
U+00A0 or U+202F, so “ignore all whitespace” means a
different set of characters than “count words” does. Under the C locale it
ignores none of them. That also explains the widely repeated complaint that
diff -w will not ignore a full-width space: it is true in some locales and false
in others, and nobody writing it down mentioned which one they were in.
Two practical consequences. First, normalisation is the safe move: NFKC turns
U+00A0, U+2009, U+202F, U+205F and
U+3000 into an ordinary space, and leaves U+200B,
U+FEFF, U+00AD and U+2028 exactly as they were, so it
fixes the spaces without touching the characters that are doing structural work. Second, do
not build a whitelist from a constant. Python’s string.whitespace is seven
ASCII characters and contains none of these; str.split() and
re both handle U+3000 correctly, so the gap is in the constant, not
in the functions.
One last thing worth knowing before you paste an example anywhere: some sites quietly rewrite
U+3000 into an ordinary space when you post it. A demonstration typed into a
comment box can come back looking completely normal, which is exactly how a character this
wide stays invisible for so long.
Paste without formatting does not help
The first thing everyone tries is Paste without formatting
(Ctrl+Shift+V) or Clear formatting. Neither
one touches these characters. Those commands strip styling — fonts, sizes, colours,
hyperlinks. A zero width space is not styling, it is a character, so it survives every
formatting command there is.
What Word and Docs show you
Both Word’s Show/Hide ¶ and Google Docs’ Show non-printing characters reveal paragraph marks, spaces and tabs. Neither reliably marks every Unicode invisible character, so do not treat a clean-looking ¶ view as proof that the text is clean. It is not proof of anything.
Removing them inside Word or Docs
Open Find and Replace (Ctrl+H), paste the actual character into
Find what, leave Replace with empty, and choose Replace All. The
Find box will look empty because the character is invisible; it is not empty. You can copy
the character from the character list.
Repeat for each character you care about — usually U+200B,
U+2060, U+00AD and U+FEFF. That is tedious, which is
why the box above exists: select the text, copy it, clean it in one pass, paste it back.
Where they come from in a document
Text pasted out of a web page, a PDF, an email, a translation tool or a chat window. Word and Docs keep what you paste, invisible characters included, and then carry them into whatever comes next: a mail merge, a find, a spell check, an export, or a paste into another system that then reports the two strings do not match.
Is anything uploaded?
No. There is no backend. The cleaning runs in this browser tab, so a confidential document never leaves your device.