Not sure if you wanted advice just on the format string, or on the iteration and stream-handling too? Here is the link to std.fmt.format (from master branch) that includes the description of the format string:
The format string must be comptime-known and may contain placeholders following this format:
{[argument][specifier]:[fill][alignment][width].[precision]}[…]
d: output numeric value in decimal notation[…]
To print literal curly braces, escape them by writing them twice, e.g.
{{or}}.
I’m new to Zig too (so not sure if it’s perfect style / idiomatically written), but I gave it a try, including handling generic streams and buffering:
const std = @import("std");
pub fn writePrintable(output: anytype, input: []const u8) !void {
for (input) |byte| {
if (byte >= 32 and byte <= 126) {
try output.writeByte(byte);
} else {
try output.print("{{{d:03}}}", .{byte});
}
}
}
pub fn main() !void {
var stdout_bufwriter = std.io.bufferedWriter(std.io.getStdOut().writer());
var stdout = stdout_bufwriter.writer();
try writePrintable(stdout, "abc\ndef\n");
try stdout.print("\n", .{});
try stdout_bufwriter.flush();
}
Output:
abc{010}def{010}
(using Zig 0.15.0-dev.847+850655f06)