Parse/validate ISBNs in Zig
README.md

isbn.zig #

A Zig library for parsing, validating, and converting International Standard Book Numbers (ISBNs) in both the 10-digit and 13-digit formats.

The API documentation is generated from the doc comments in the source and published at https://jeff.jcollie.page/isbn.zig/. To read it locally instead, zig build docs builds it into zig-out/docs and zig build docs-serve serves it on http://127.0.0.1:8000/. A server is needed rather than opening the files directly, because the viewer fetches sources.tar and main.wasm at runtime and a browser refuses those from a file:// page.

Features #

  • Parse ISBNs from text, with or without - separators.
  • Validate check digits during parsing (including the X check digit used by ISBN-10).
  • Compute check digits, optionally using SIMD vector operations.
  • Upgrade an ISBN-10 to its equivalent ISBN-13.
  • Compare ISBNs across formats: an ISBN-10 is equal to its 13-digit equivalent.
  • Format ISBNs with proper hyphenation, using the International ISBN Agency's registration group and registrant range data.

Requirements #

  • Zig 0.16.0 or later

Installation #

Add the dependency to your project:

zig fetch --save git+https://tangled.org/jcollie.dev/isbn.zig

Then wire it up in your build.zig:

const isbn = b.dependency("isbn", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("isbn", isbn.module("isbn"));

Usage #

const ISBN = @import("isbn").ISBN;

// Parsing validates the check digit.
const ten: ISBN = try .parse("0-306-40615-2");
const thirteen: ISBN = try .parse("978-0-306-40615-7");

// Upgrade an ISBN-10 to an ISBN-13.
const upgraded = ten.upgrade();

// Comparison works across formats.
std.debug.assert(ten.eql(&thirteen));

// Hyphenate explicitly, or format with {f}.
var buf: [ISBN.max_hyphenated_len]u8 = undefined;
const hyphenated = try upgraded.hyphenate(&buf);
std.debug.print("{s}\n", .{hyphenated}); // 978-0-306-40615-7
std.debug.print("{f}\n", .{ten}); // 0-306-40615-2

parse returns error.ParseError for malformed input and error.InvalidCheckDigit when the check digit doesn't match.

Build options #

  • -Dsimd=[bool] — use SIMD vector operations for computing check digits (default: false). It is off because it does not pay: zig build bench measures both implementations, and nine or twelve lanes of multiply-and-add do not earn back the cost of widening the digits and assembling the vector.
  • -Ddocs-port=[u16] — port for zig build docs-serve (default: 8000).

Standards #

Standard Title Support in isbn.zig
ISO 2108 International Standard Book Number Parsing and validating both the 10- and 13-digit forms, the two check digit algorithms, and conversion from 10 to 13
ISBN range message Registration group and registrant ranges Hyphenation, from the International ISBN Agency's published ranges, generated into src/ranges.zig
EAN/UPC (GS1) Article numbering The 978 and 979 prefixes an ISBN-13 is built on

ISO 2108 itself is not freely available. The check digit algorithms and the 978/979 prefixes are documented in the ISBN Users' Manual, which is: https://www.isbn-international.org/content/isbn-users-manual

Range data #

Hyphenation uses the registration group and registrant ranges published by the International ISBN Agency, embedded at build time as src/ranges.zig. To update them:

zig build update-ranges

Testing #

zig build test

The test suite includes unit tests and a fuzz test.

zig build check compiles everything that zig build test does not run — the benchmark, the documentation server, and the range generator — so that none of them can quietly stop compiling.

zig build bench compares the SIMD and scalar check digit implementations against each other; it calls both directly, so the -Dsimd setting does not affect what it measures.

License #

MIT. This project is compliant with the REUSE Specification.