pyunormalize
The pyunormalize package is a pure-Python, zero-dependency implementation of the Unicode normalization algorithm.
It supports the four standard Unicode normalization forms:
- NFC
- NFD
- NFKC
- NFKD
The package uses generated lookup tables derived from the Unicode Character Database (UCD) for Unicode 18.0.0, released in September 2026. It is therefore independent of the unicodedata module and the specific Unicode database version bundled with the Python runtime on which it is installed.
All four normalization forms are tested against the official Unicode NormalizationTest.txt test file.
Requirements
Python 3.9 or newer.
Installation
Install the package with:
pip install pyunormalize
Upgrade to the latest version with:
pip install --upgrade pyunormalize
Public API
The public API exposes the four normalization functions and a generic dispatcher:
from pyunormalize import NFC, NFD, NFKC, NFKD, normalize
It also exposes constants for the Unicode version in use:
from pyunormalize import UCD_VERSION, UNICODE_VERSION
Note that UCD_VERSION and UNICODE_VERSION are aliases referring to the same version string ('18.0.0').
Usage examples
Below are practical examples illustrating how to normalize Unicode strings using either dedicated functions or the generic dispatcher.
Dedicated functions
Use the convenience functions NFC, NFD, NFKC, or NFKD for direct normalization:
from pyunormalize import NFC, NFD, NFKC, NFKD
text = "désaffiliât"
assert text == NFC(text)
def hex_repr(string):
return " ".join([f"{ord(c):04X}" for c in string])
print(f"NFD : {hex_repr(NFD(text))}")
print(f"NFKD : {hex_repr(NFKD(text))}")
print(f"NFC : {hex_repr(NFC(text))}")
print(f"NFKC : {hex_repr(NFKC(text))}")
Output:
NFD : 0064 0065 0301 0073 0061 FB03 006C 0069 0061 0302 0074
NFKD : 0064 0065 0301 0073 0061 0066 0066 0069 006C 0069 0061 0302 0074
NFC : 0064 00E9 0073 0061 FB03 006C 0069 00E2 0074
NFKC : 0064 00E9 0073 0061 0066 0066 0069 006C 0069 00E2 0074
Generic normalize function
When the normalization form is specified dynamically at runtime, use normalize(form, text):
from pyunormalize import normalize
text = "fluffiness"
# The `form` parameter accepts "NFC", "NFD", "NFKC", or "NFKD" (case-sensitive)
nfkd_text = normalize("NFKD", text)
print(nfkd_text)
Output:
fluffiness
Related resources
This implementation is based on the following resources:
- The Unicode Standard, Version 18.0 – Core Specification, Section 3.11: “Normalization Forms”
- Unicode Standard Annex #15: “Unicode Normalization Forms,” revision 58
Changelog
See the CHANGELOG for the latest updates and changes.
Licenses
The code is available under the terms of the MIT License.
The use of Unicode data files is governed by the UNICODE TERMS OF USE. Further specifications of rights and restrictions pertaining to the use of the Unicode data files and software can be found in the Unicode License v3, a copy of which is included as UNICODE-LICENSE.
Release files for pyunormalize 18.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyunormalize-18.0.0.tar.gz | 575.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyunormalize-18.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 653.4 kB
Release files / pyunormalize-18.0.0.tar.gz
| Download URL | pyunormalize-18.0.0.tar.gz |
|---|---|
| Size | 575.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2b2e65201e688bb38c66ab66ef1071cc07b32e9840e5ae07aab716db6ede7d6d
|
|
BLAKE2b-256 checksum How to use checksums |
49645c8ce34a4e366ee052ce7b3b2ddd11b9711a072902a31d0385f3a0f394e8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / pyunormalize-18.0.0-py3-none-any.whl
| Download URL | pyunormalize-18.0.0-py3-none-any.whl |
|---|---|
| Size | 78.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cdc571ab761c2bd905275c9f3e3cf386d10b4f9bc8d55b32d410cc635e684ba8
|
|
BLAKE2b-256 checksum How to use checksums |
fb0a5370bd67bdfc4acf97f25b08cb6fbcb7e898fa391716535c60b4bd761492
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|