From e0259f43a726f61da14686de802021fcdb9aacd0 Mon Sep 17 00:00:00 2001 From: Chris Boesch Date: Fri, 3 Apr 2026 13:35:56 +0200 Subject: Insert space for additional async exercises --- exercises/102_formatting.zig | 140 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 exercises/102_formatting.zig (limited to 'exercises/102_formatting.zig') diff --git a/exercises/102_formatting.zig b/exercises/102_formatting.zig new file mode 100644 index 0000000..be16978 --- /dev/null +++ b/exercises/102_formatting.zig @@ -0,0 +1,140 @@ +// +// Terminals have come a long way over the years. Starting with +// monochrome lines on flickering CRT monitors and continuously +// improving to today's modern terminal emulators with sharp +// images, true color, fonts, ligatures, and characters in every +// known language. +// +// Formatting our results to be appealing and allow quick visual +// comprehension of the information is what users desire. <3 +// +// C set string formatting standards over the years, and Zig is +// following suit and growing daily. Due to this growth, there is +// no official documentation for standard library features such +// as string formatting. +// +// Therefore, the comments for the format() function are the only +// way to definitively learn how to format strings in Zig: +// +// https://codeberg.org/ziglang/zig/src/branch/master/lib/std/Io/Writer.zig#L537 +// +// Zig already has a very nice selection of formatting options. +// These can be used in different ways, but generally to convert +// numerical values into various text representations. The results +// can be used for direct output to a terminal or stored for +// later use or written to a file. The latter is useful when +// large amounts of data are to be processed by other programs. +// +// In Ziglings, we are concerned with the output to the console. +// But since the formatting instructions for files are the same, +// what you learn applies universally. +// +// Since we write to "debug" output in Ziglings, our answers +// usually look something like this: +// +// print("Text {placeholder} another text \n", .{foo}); +// +// In addition to being replaced with foo in this example, the +// {placeholder} in the string can also have formatting applied. +// How does that work? +// +// This actually happens in several stages. In one stage, escape +// sequences are evaluated. The one we've seen the most +// (including the example above) is "\n" which means "line feed". +// Whenever this statement is found, a new line is started in the +// output. Escape sequences can also be written one after the +// other, e.g. "\n\n" will cause two line feeds. +// +// By the way, the result of these escape sequences is passed +// directly to the terminal program. Other than translating them +// into control codes, escape sequences have nothing to do with +// Zig. Zig knows nothing about "line feeds" or "tabs" or +// "bells". +// +// The formatting that Zig *does* perform itself is found in the +// curly brackets: "{placeholder}". Formatting instructions in +// the placeholder will determine how the corresponding value, +// e.g. foo, is displayed. +// +// And this is where it gets exciting, because format() accepts a +// variety of formatting instructions. It's basically a tiny +// language of its own. Here's a numeric example: +// +// print("Catch-0x{x:0>4}.", .{twenty_two}); +// +// This formatting instruction outputs a hexadecimal number with +// leading zeros: +// +// Catch-0x0016. +// +// Or you can center-align a string like so: +// +// print("{s:*^20}\n", .{"Hello!"}); +// +// Output: +// +// *******Hello!******* +// +// Let's try making use of some formatting. We've decided that +// the one thing missing from our lives is a multiplication table +// for all numbers from 1-15. We want the table to be nice and +// neat, with numbers in straight columns like so: +// +// X | 1 2 3 4 5 ... +// ---+---+---+---+---+---+ +// 1 | 1 2 3 4 5 +// +// 2 | 2 4 6 8 10 +// +// 3 | 3 6 9 12 15 +// +// 4 | 4 8 12 16 20 +// +// 5 | 5 10 15 20 25 +// +// ... +// +// Without string formatting, this would be a more challenging +// assignment because the number of digits in the numbers varies +// from 1 to 3. But formatting can help us with that. +// +const std = @import("std"); +const print = std.debug.print; + +pub fn main() !void { + // Max number to multiply + const size = 15; + + // Print the header: + // + // We start with a single 'X' for the diagonal. + print("\n X |", .{}); + + // Header row with all numbers from 1 to size. + for (0..size) |n| { + print("{d:>3} ", .{n + 1}); + } + print("\n", .{}); + + // Header column rule line. + var n: u8 = 0; + while (n <= size) : (n += 1) { + print("---+", .{}); + } + print("\n", .{}); + + // Now the actual table. (Is there anything more beautiful + // than a well-formatted table?) + for (0..size) |a| { + print("{d:>2} |", .{a + 1}); + + for (0..size) |b| { + // What formatting is needed here to make our columns + // nice and straight? + print("{???} ", .{(a + 1) * (b + 1)}); + } + + // After each row we use double line feed: + print("\n\n", .{}); + } +} -- cgit v1.2.3