Non-breaking space vs space: U+00A0 and  

It looks like a space, it acts like a space when you read it, and your code insists it is something else. It probably is: a non-breaking space.

The two spaces

Ordinary spaceNon-breaking space
Code pointU+0020U+00A0
HTMLa real space, or    or  
Line wrappingThe browser may break the line hereThe browser should not break the line here
Looks likeA gapThe same gap
" " === chartruefalse

There are other space-like characters too (thin space, figure space, ideographic space) but U+00A0 is the one you will meet every week.

Where it comes from

What breaks

"10\u00A0MB".split(" ")     // ["10\u00A0MB"]  — one piece, not two
"10\u00A0MB".replace(" ", "") // "10\u00A0MB"   — nothing removed
"10\u00A0MB".replace(/\s/g, "") // "10MB"     — \s does match NBSP

"10\u00A0MB".split()          # Python: split() with no argument *does* split on NBSP
"10\u00A0MB".split(" ")       # Python: ["10\u00A0MB"]  — literal space only
OperationOrdinary spaceNBSP
JavaScript / Python trim() / strip()Removed at the endsRemoved at the ends
Regex \s (JS; Python 3 without re.ASCII)MatchesMatches
Literal " " in split / replaceMatchesDoes not match
Python str.split() with no argumentsSplitsSplits
CSS white-space wrappingMay wrapShould stay together

That last row is why people use it on purpose. The rows above are why a CSV parser, a “split on space” tokenizer or a unit test then fails on text copied from a web page.

How to normalise it

text = text.replace("\u00a0", " ")          # Python
text = text.replace(/\u00A0/g, " ")         // JavaScript
# or replace every Unicode space separator with an ordinary space:
import unicodedata, sys
text = "".join(" " if unicodedata.category(c) == "Zs" else c for c in text)

Paste the two “identical” lines into the text diff to see the NBSP show up as a change. The word and character counter counts it as a character. For a named report (it flags spaces and invisibles separately) use Anvil /v1/text/inspect on non-secret text.

A zero-width space is a different problem: it is not a space at all, and trim() will not remove it. See invisible zero-width characters.

Related

SMS counter: find non-breaking spaces that cost you a text · Invisible zero-width characters · Strings that look the same but are not equal · Invisible characters in a password · Look-alike (homoglyph) characters · Text diff · Wirebook: invisible characters

Questions

What is a non-breaking space?

Unicode character U+00A0, written in HTML as  . It looks like a normal space but stops the browser breaking the line at that point, and it is a different character in code.

Why does replace(' ', '') not remove a space I can see?

That space is probably U+00A0, not U+0020. replace(' ', '') only removes ordinary spaces. Use a regex \s or an explicit replace of \u00A0.

Does trim() remove non-breaking spaces?

Yes. JavaScript trim() and Python strip() treat U+00A0 as whitespace, so they remove it from the ends. They will not remove a zero-width space.

Why do Word and Excel insert non-breaking spaces?

Word processors use them to keep numbers, units and names together on one line. Copying out of a document or a formatted spreadsheet cell brings them with you.

How do I find non-breaking spaces in a file?

Search for \u00A0 or \xa0 in your editor, or paste into the text diff against a version typed by hand. In Python, '\\u00a0' in repr(s) gives them away.

Published · updated .

Try it

Related guides

Newest guides