Skip to content
Shaik Abdul Thouhid edited this page May 31, 2026 · 4 revisions

ezicode

A Unicode engine for Zig. Unicode 17.

ezicode handles the character side of text: encoding, codepoint properties, normalization, segmentation, casing, scripts, and display width. The tables are baked at compile time into the binary; nothing initializes at startup and nothing allocates to answer property questions.

It does not handle locale formatting. Dates, numbers, currencies, plurals, calendars, transliteration — that's a separate beast to tackle, this humble little library hopes to build foundation to build or try bringing cldr into zig space. 'If' your project needs it, wrap ICU4X or ICU4C above ezicode and call into them for the locale layer. The abstraction is as minimum as possible. The conventions are kept bare minimum and are documented, but if found some which are not, please raise an issue.

What's included

  • UTF-8, UTF-16, UTF-32 encode and decode, with transcoding between all three
  • Codepoint properties (general category, scripts, derived core properties, numeric, etc.) via page-table lookup
  • Grapheme, word, sentence, and line break iterators conforming to UAX #29 and UAX #14
  • Canonical and compatibility normalization (NFC/NFD/NFKC/NFKD), batch and zero-allocation streaming
  • Case folding (simple and full), plus locale-specific case mapping for Turkish, Azeri, and Lithuanian
  • Script and Script_Extensions queries with zero-allocation returns
  • Display width that respects East Asian Width and combining marks

What's not included

  • Collation (UTS #10). On the roadmap. Root DUCET only; tailoring is CLDR.
  • Anything in CLDR. Wrap ICU above ezicode for that, will provide a clean interface to plug-in icu4x library with ezicode.

Install

// build.zig.zon
.{
    .name = .your_project,
    .dependencies = .{
        .ezicode = .{
            .url = "https://github.com/<user>/ezicode/archive/<commit>.tar.gz",
            .hash = "...",
        },
    },
}
// build.zig
const ezicode = b.dependency("ezi_code", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("ezi_code", ezicode.module("ezi_code"));
// in your code
const unicode = @import("ezi_code").unicode;
const casing = unicode.casing;
const segmentation = unicode.segmentation;

const text = "Hello, 世界! 👋🏽";

var graphemes = segmentation.graphemes(text);
while (graphemes.next()) |cluster| {
    // cluster is a []const u8 slice into `text`
}

const folded = try casing.foldFull(allocator, "STRAßE");
defer allocator.free(folded);
// folded == "strasse"

Status

0.x. Feature-complete on the UCD surface except for bidi and collation. The API is not yet stable and may change between minor versions until 1.0. Conformance is verified against the official UCD test corpora on every build.

Currently tracks Zig 0.17.0-dev. Will pin to 0.17.0 when that lands.

Why another one?

There are already two Zig Unicode libraries worth knowing about: zg and uucode. Both are well-built and have shipped real software. UCD space though is moving target, the surface is pretty small and both uucode and zg cover them pretty well. But ezi-code aims to be a zig-native complete text-processing library.

ezicode picks compile-time-const tables instead. Everything lives in .rodata, no initialization runs, no allocator is needed for property questions, and the data is thread-safe by construction. The tradeoff is a larger binary and longer compile times for the codegen step that produces the tables.

If that tradeoff fits your project, ezicode might be a better fit. If it doesn't, the alternatives above are good choices and I'd recommend them honestly.

Where to next

The original goal was to create a de-facto zig-native text processing library with complete UCD features.

Clone this wiki locally