Formatting
const std = @import("std");
const expect = std.testing.expect;
test "bufPrint formats into memory you own" {
var buf: [64]u8 = undefined;
const text = try std.fmt.bufPrint(&buf, "{s} is {d}", .{ "answer", 42 });
try expect(std.mem.eql(u8, text, "answer is 42"));
}
test "common specifiers" {
var buf: [64]u8 = undefined;
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{d}", .{255}), "255"));
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{x}", .{255}), "ff"));
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{X}", .{255}), "FF"));
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{b}", .{5}), "101"));
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{o}", .{8}), "10"));
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{c}", .{@as(u8, 'A')}), "A"));
}
test "width, alignment and fill" {
var buf: [64]u8 = undefined;
// {[fill][align][width]}: align is <, ^ or >.
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{d:5}", .{42}), " 42"));
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{d:<5}", .{42}), "42 "));
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{d:^5}", .{42}), " 42 "));
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{d:0>5}", .{42}), "00042"));
}
test "float precision" {
var buf: [64]u8 = undefined;
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{d:.2}", .{3.14159}), "3.14"));
}
test "escaping braces" {
var buf: [64]u8 = undefined;
try expect(std.mem.eql(u8, try std.fmt.bufPrint(&buf, "{{{d}}}", .{1}), "{1}"));
}
test "allocPrint when the length is unknown" {
const gpa = std.testing.allocator;
const text = try std.fmt.allocPrint(gpa, "{d}-{d}", .{ 1, 2 });
defer gpa.free(text);
try expect(std.mem.eql(u8, text, "1-2"));
}Where the output goes
| Function | Writes to |
|---|---|
bufPrint | a buffer you supply (no allocation) |
allocPrint | fresh memory (caller frees) |
writer.print | any writer |
bufPrint returns a slice of the part it filled, and fails with
error.NoSpaceLeft rather than truncating.
Specifiers
| Spec | Meaning |
|---|---|
{d} | decimal |
{x} / {X} | lower / upper hex |
{b} / {o} | binary / octal |
{s} | string |
{c} | a byte as a character |
{any} | structural dump |
Width, alignment, precision
The form is {[fill][align][width]}, with < ^ > for alignment:
"{d:5}" // " 42" (right by default for numbers)
"{d:<5}" // "42 "
"{d:^5}" // " 42 "
"{d:0>5}" // "00042"
"{d:.2}" // "3.14"
Escape a literal brace by doubling it: {{ and }}.
Checked at compile time
The format string is a comptime parameter, so the argument count and each
specifier are validated against the argument types during compilation. A {d}
pointed at a string does not compile. There is no runtime format-string
failure mode to worry about.