# Unicode NO-BREAK SPACE not normalized by normalize\_space/2

**URL:** <https://swi-prolog.discourse.group/t/unicode-no-break-space-not-normalized-by-normalize-space-2/9800>\
**Category:** General\
**Tags:** bug\
**Created:** [August 28, 2026, 2:55am UTC](https://swi-prolog.discourse.group/t/unicode-no-break-space-not-normalized-by-normalize-space-2/9800 "2026-08-28T02:55:52Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![mike.elston](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/mike.elston/32/3691_2.png) [@mike.elston](https://swi-prolog.discourse.group/u/mike.elston)\
**Post date:** [August 28, 2026, 2:55am UTC](https://swi-prolog.discourse.group/t/unicode-no-break-space-not-normalized-by-normalize-space-2/9800/1 "2026-08-28T02:55:52Z")

</div>

The documentation for normalize\_space/2 says:

All non-empty sequences for Unicode white space characters are replaced by a single space (`\u0020`) character.

but

atom\_codes(A, [0x00A0]),normalize\_space(atom(X),A).  
A = X, X = ’ '.

> **[Unicode Characters in the Space Separator Category](https://unicodeplus.com/category/Zs)**
>
> List of the 17 unicode characters of the Space Separator category.

Thanks

Mike

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 28, 2026, 11:44am UTC](https://swi-prolog.discourse.group/t/unicode-no-break-space-not-normalized-by-normalize-space-2/9800/2 "2026-08-28T11:44:09Z")

</div>

Thanks. The space detection was reusing the Prolog parser separator detection. That detection changed with recent Unicode updates to follow the Unicode recommendations for separators in source code. Now it uses the locale dependent code\_type/2 `space` class.

---

<div class="post-metadata">

**Author:** ![mike.elston](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/mike.elston/32/3691_2.png) [@mike.elston](https://swi-prolog.discourse.group/u/mike.elston)\
**Post date:** [August 28, 2026, 10:26pm UTC](https://swi-prolog.discourse.group/t/unicode-no-break-space-not-normalized-by-normalize-space-2/9800/3 "2026-08-28T22:26:29Z")

</div>

> [@mike.elston](#):
>
> atom\_codes(A, [0x00A0]),normalize\_space(atom(X),A).

Thanks Jan. However this didn’t solve my problem and now I am confused.

You say “now it uses the locale dependent [code\_type/2](https://www.swi-prolog.org/pldoc/doc_for?object=code_type/2 "Tests or generates alternative Types or Char/Codes.") `space` class”.

The doc for code\_type/2 says:

The types are sensitive to the active _locale_, see [setlocale/3](https://www.swi-prolog.org/pldoc/man?predicate=setlocale/3).

My locale: setlocale(ctype,A,A).  
A = ' **en\_US.UTF-8’.**

According to Google:

In the **`en_US.UTF-8`** locale, there are exactly **29 characters** recognized as white space under standard [Unicode rules](https://en.wikipedia.org/wiki/Whitespace_character) and POSIX wide-character classification (`iswspace`). [[1](https://en.wikipedia.org/wiki/Whitespace_character), [2](https://beej.us/guide/bgc/html/split/unicode-wide-characters-and-all-that.html)].

…

**3. C1 Control and Latin-1 Spacing**

Multi-byte spaces derived from the extended Latin-1 standard block. [[1](https://en.wikipedia.org/wiki/Whitespace_character)]

| **Code Point** | **Character Name** | **UTF-8 Bytes** |
| --- | --- | --- |
| **`U+0085`** | Next Line (NEL) | `C2 85` |
| **`U+00A0`** | No-Break Space (NBSP) | `C2 A0` |

So I expect NBSP to be included but code\_type/2 doesn’t agree:

code\_type(A,space),format(‘0x~16R~n’,[A]),fail.  
0x9  
0xA  
0xB  
0xC  
0xD  
0x20  
0x1680  
0x2000  
0x2001  
0x2002  
0x2003  
0x2004  
0x2005  
0x2006  
0x2008  
0x2009  
0x200A  
0x2028  
0x2029  
0x205F  
0x3000

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [August 29, 2026, 3:38pm UTC](https://swi-prolog.discourse.group/t/unicode-no-break-space-not-normalized-by-normalize-space-2/9800/4 "2026-08-29T15:38:41Z")

</div>

It took a little while. With help from Claude the character classification is now detached from libc and controlled by our own tables generated from the Unicode data. This makes the classification locale independent and portable. As is, NBSP is classified as blank in BSD Unix (derived) systems and not in Linux. There is something to say for that, but I think it is a good idea that SWI-Prolog takes a platform independent decision (which is to make them blank).

---

<div class="post-metadata">

**Author:** ![mike.elston](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/mike.elston/32/3691_2.png) [@mike.elston](https://swi-prolog.discourse.group/u/mike.elston)\
**Post date:** [August 29, 2026, 8:06pm UTC](https://swi-prolog.discourse.group/t/unicode-no-break-space-not-normalized-by-normalize-space-2/9800/5 "2026-08-29T20:06:36Z")

</div>

> [@mike.elston](#):
>
> atom\_codes(A, [0x00A0]),normalize\_space(atom(X),A).

Wow! The only way around was through. Thanks Jan.
