#Print digit separators
1 messages · Page 1 of 1 (latest)
I don't think there's a formatter for it in std, but it should be fairly easy to do yourself
Negative ints and generic types left as an exercise for the reader :)
const std = @import("std");
fn formatIntSep(n: u64, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
// Count digits
var x = n;
var exp: u64 = 1;
var digits: std.math.Log2Int(u64) = 0;
while (x > 0) {
x /= 10;
exp *= 10;
digits += 1;
}
// Print integer
if (digits == 0) {
return writer.writeAll("0");
}
while (digits > 0) {
exp /= 10;
digits -= 1;
try writer.writeByte('0' + @intCast(u8, n / exp % 10));
if (digits > 0 and digits % 3 == 0) {
try writer.writeByte('\'');
}
}
}
fn fmtIntSep(n: u64) std.fmt.Formatter(formatIntSep) {
return .{ .data = n };
}
test "formatIntSep" {
var buf = std.ArrayList(u8).init(std.testing.allocator);
defer buf.deinit();
try buf.writer().print("{}", .{fmtIntSep(123456789)});
try std.testing.expectEqualStrings("123'456'789", buf.items);
}```
Awesome. Thanks!
just a note: std.fmt.Formatter is nice for the simple case, but for more complex use cases it is often more flexible to just define your own struct, where you can have extra metadata to inform the formatting behaviour (as opposed to only having access to the formatting target).
E.g.
const std = @import("std");
const FmtIntSep = struct {
n: u64,
negative: bool,
pub fn format(
formatter: FmtIntSep,
comptime fmt_str: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
// ...
}
};
fn fmtIntSep(val: anytype) FmtIntSep {
return .{
.n = std.math.absCast(val),
.negative = val < 0,
};
}
you could also add a field like sep: u8 which would be supplied as an extra argument to fmtIntSep, to allow for different separators. Could also make the struct generic over the integer type. There's a lot of things you can play with.
[...] can have extra metadata [...]
You can do that with std.fmt.Formatter too, seestd.fmt.fmtDuration
It becomes somewhat less useful at that point though, so you can use your own struct instead if you prefer
sure, but you'll notice that what it actually ends up doing is just defining its own struct anyway - std.fmt.Formatter is kind of superfluous there