This is the documentation for the latest development branch of MicroPython and may refer to features that are not available in released versions.

If you are looking for the documentation for a specific release, use the drop-down menu on the left and select the desired version.

Unicode Support

MicroPython provides Unicode support for strings, with the level of support depending on the build configuration.

Terminology

This document uses the following Unicode terms:

  • Code point: a single Unicode value in the range U+0000 to U+10FFFF, for example U+0041 A or U+1F600 😀. MicroPython strings are sequences of code points.

  • Character: informally used to mean a code point. Be aware that a user-perceived character (a grapheme) may consist of several code points, such as a base letter followed by combining marks.

  • Byte: a single 8-bit value. In UTF-8 each code point is stored as one to four bytes (see below).

Operations such as len(), indexing and slicing act on code points, not on graphemes or display width, so a base letter followed by a combining mark counts as two code points.

Character Encoding

MicroPython uses UTF-8 encoding for all strings. When Unicode support is enabled (MICROPY_PY_BUILTINS_STR_UNICODE), strings can contain any valid Unicode code point from U+0000 to U+10FFFF.

ASCII characters (0-127) are stored in a single byte, making them as memory-efficient as on systems without Unicode support. Multi-byte UTF-8 code points use 2-4 bytes depending on the code point:

  • U+0000 to U+007F: 1 byte (ASCII)

  • U+0080 to U+07FF: 2 bytes

  • U+0800 to U+FFFF: 3 bytes

  • U+10000 to U+10FFFF: 4 bytes

Encoding and Decoding

The bytes.decode() and str.encode() methods support the following encodings:

  • UTF-8 ('utf-8' or 'utf8')

  • ASCII ('ascii')

Other encodings (such as 'latin-1', 'utf-16', etc.) are not supported and will raise LookupError.

Example:

>>> '日本語'.encode('utf-8')
b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e'
>>> b'\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e'.decode('utf-8')
'日本語'

Error Handling

When decoding bytes that contain invalid UTF-8 sequences, the errors parameter of bytes.decode() controls the behavior:

  • 'strict' (default): Raise UnicodeError

  • 'ignore': Skip invalid bytes (requires MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS)

  • 'replace': Replace invalid bytes with U+FFFD � (requires MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS)

Example:

>>> # Strict mode (default) raises an error
>>> b'hello\xffworld'.decode('utf-8')
UnicodeError: invalid UTF-8

>>> # Ignore mode skips invalid bytes
>>> b'hello\xffworld'.decode('utf-8', 'ignore')
'helloworld'

>>> # Replace mode substitutes replacement character
>>> b'hello\xffworld'.decode('utf-8', 'replace')
'hello�world'

For memory-conscious applications, consider using 'ignore' mode when processing untrusted or partially corrupted data, as it avoids raising exceptions while still recovering valid text.

The same errors handling applies when decoding any bytes-like object, including via the str() constructor (for example str(buf, 'utf-8', 'replace') where buf is a bytes, bytearray, memoryview or array object).

String Methods

When Unicode support is enabled, string methods operate on code points rather than bytes:

  • str.center() - Counts code points for width calculation

  • len(s) - Returns number of code points (not bytes)

  • String indexing and slicing work on code-point boundaries

  • No support for display width calculations (East Asian width, combining characters, etc.)

Example:

>>> s = 'Hello 世界'
>>> len(s)           # 8 code points
8
>>> len(s.encode())  # 12 bytes
12
>>> s.center(12)     # Centered by code-point count
'  Hello 世界  '

String Formatting

The %c format specifier and {:c} format code support full Unicode:

  • Accepts code points from 0 to 0x10FFFF

  • Properly encodes multi-byte UTF-8 code points

  • Raises ValueError for invalid code points

Example:

>>> '%c' % 65           # ASCII
'A'
>>> '%c' % 0x03B1       # Greek α
'α'
>>> '%c' % 0x1F600      # Emoji 😀
'😀'
>>> '{:c}'.format(0x4E2D)  # Chinese 中
'中'

>>> # Invalid code point
>>> '%c' % 0x110000
ValueError: %c arg not in range(0x110000)

F-strings also support the :c format code:

>>> code_point = 0x2665  # Heart suit ♥
>>> f'I {code_point:c} Python'
'I ♥ Python'

Build Configuration

Unicode features are controlled by several build-time flags in mpconfigport.h:

MICROPY_PY_BUILTINS_STR_UNICODE

Enable Unicode string support. When enabled, strings can contain any valid Unicode character and string operations work on character boundaries rather than byte boundaries.

Default: Enabled at MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES and above.

MICROPY_PY_BUILTINS_STR_UNICODE_CHECK

Enable UTF-8 validation during string operations. When disabled, string operations may produce incorrect results with invalid UTF-8 sequences.

Default: Follows MICROPY_PY_BUILTINS_STR_UNICODE setting.

MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS

Enable the 'ignore' and 'replace' error handlers for bytes.decode(). When enabled, invalid UTF-8 bytes can be either skipped ('ignore') or replaced with U+FFFD ('replace').

Default: Enabled at MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES and above.

Example Configuration

For a constrained port with limited flash, disable error handlers:

#define MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS (0)

For a port with more resources, enable all Unicode features:

#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
// This automatically enables:
// - MICROPY_PY_BUILTINS_STR_UNICODE
// - MICROPY_PY_BUILTINS_BYTES_DECODE_ERRORS

Limitations

MicroPython’s Unicode support has some limitations compared to CPython:

  • Only UTF-8 and ASCII encodings are supported

  • No support for Unicode normalization

  • No locale-aware string operations

  • The errors parameter accepts only positional arguments (not keyword arguments)

  • String methods like upper(), lower(), etc. work correctly only for ASCII

  • The MicroPython interactive REPL and input() function currently have limited Unicode support. The line editor is unaware of the displayed width of characters: wide characters (for example many CJK characters) take two terminal columns, while a grapheme cluster (a base code point plus combining marks, or an emoji sequence) can span several code points yet occupy a single column. Because editing tracks code points rather than displayed columns, line-editing keys such as backspace and the left/right arrows may leave the cursor misaligned with the text shown on screen. A workaround is to place the Unicode text in a UTF-8 encoded MicroPython script and run it using mpremote run <script.py>.