Remove Invisible Characters from Word and Google Docs

0 characters
Options

Leave aggressive mode off unless the text is prose you are willing to rewrite; on codes, IDs and reference numbers it can do damage.

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.

CharacterAdvance width at 16 px
Ordinary space U+00204.73 px
No-break space U+00A04.73 px
Thin space U+20093.20 px
Narrow no-break space U+202F2.38 px
Medium mathematical space U+205F3.56 px
Ideographic space U+300016.00 px
Capital letter A, for scale11.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.

SeparatorThis page’s counterUnicode word segmentationwc -w, UTF-8 localeawk fieldsdiff -w ignores it
Ordinary space U+00205555baseline
No-break space U+00A05551no
Thin space U+20095551yes
Narrow no-break space U+202F5151no
Medium mathematical space U+205F5551yes
Ideographic space U+30005551yes
Zero width space U+200B1511no
Zero width no-break space U+FEFF5111no
Line separator U+20285551yes
Soft hyphen U+00AD1111no

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.