⚡ Zig Guide LiveUnofficial
✓ Zig 0.17.0-dev.1454+5faa79730On an older Zig?

Parsing and Encoding

const std = @import("std");
const expect = std.testing.expect;
const expectError = std.testing.expectError;
const expectEqualStrings = std.testing.expectEqualStrings;

test "parseInt" {
    try expect(try std.fmt.parseInt(i32, "-42", 10) == -42);

    // Base 0 reads the prefix like a Zig literal: 0x, 0o, 0b, or decimal.
    try expect(try std.fmt.parseInt(u32, "0xff", 0) == 255);
    try expect(try std.fmt.parseInt(u32, "0b1010", 0) == 10);

    // Underscore separators are accepted, like Zig literals.
    try expect(try std.fmt.parseInt(u32, "1_000_000", 10) == 1_000_000);
}

test "parse failures are errors, not zeros" {
    try expectError(error.InvalidCharacter, std.fmt.parseInt(u8, "12a", 10));
    // The target type bounds the parse: 300 does not fit in a u8.
    try expectError(error.Overflow, std.fmt.parseInt(u8, "300", 10));
}

test "parseFloat" {
    try expect(try std.fmt.parseFloat(f64, "3.25") == 3.25);
    try expect(try std.fmt.parseFloat(f64, "-1e-3") == -0.001);
    try expect(std.math.isInf(try std.fmt.parseFloat(f32, "inf")));
}

test "hex" {
    const bytes = [_]u8{ 0xde, 0xad, 0xbe, 0xef };

    // bytesToHex returns a fixed-size array: the length is known at
    // compile time from the input, so no allocator is needed.
    const hex = std.fmt.bytesToHex(bytes, .lower);
    try expectEqualStrings("deadbeef", &hex);

    var back: [4]u8 = undefined;
    _ = try std.fmt.hexToBytes(&back, "deadbeef");
    try expect(std.mem.eql(u8, &back, &bytes));
}

test "base64" {
    const codec = std.base64.standard;

    var enc_buf: [16]u8 = undefined;
    const encoded = codec.Encoder.encode(&enc_buf, "zig");
    try expectEqualStrings("emln", encoded);

    var dec_buf: [16]u8 = undefined;
    const n = try codec.Decoder.calcSizeForSlice(encoded);
    try codec.Decoder.decode(dec_buf[0..n], encoded);
    try expectEqualStrings("zig", dec_buf[0..n]);
}

test "url_safe base64 for tokens and file names" {
    // standard base64 emits + and /, which break URLs and paths.
    const bytes = [_]u8{ 0xfb, 0xff };
    var buf: [8]u8 = undefined;
    try expectEqualStrings("+/8=", std.base64.standard.Encoder.encode(&buf, &bytes));
    try expectEqualStrings("-_8=", std.base64.url_safe.Encoder.encode(&buf, &bytes));
}

Parsing is fallible, and says so

std.fmt.parseInt returns an error union, so a bad character or an out-of-range value is a value you handle, never a silent zero. The target type is the bound: parseInt(u8, "300", 10) is error.Overflow because 300 does not fit. Passing base 0 reads the prefix the way a Zig literal would: 0x, 0o, 0b, or decimal, underscores allowed.

parseFloat accepts the usual decimal and scientific forms plus inf and nan.

Hex

bytesToHex returns a fixed-size array, not a slice, because the output length is known from the input at compile time. That means no allocator and no failure path. hexToBytes goes the other way into a caller-provided buffer.

base64: pick the alphabet for the destination

std.base64.standard uses + and /, which are fine in a MIME body and wrong in a URL or a file name. std.base64.url_safe swaps them for - and _. Both expose an Encoder and a Decoder; decoding is fallible because the input might not be valid base64. Size the destination with Decoder.calcSizeForSlice before decoding.

CodecEmitsUse for
standardA-Za-z0-9+/MIME, email, data URIs
url_safeA-Za-z0-9-_URLs, file names, tokens
*_no_padabove, no =fixed-width IDs