summaryrefslogtreecommitdiff
path: root/exercises/102_formatting.zig
diff options
context:
space:
mode:
authorChris Boesch <chrboesch@noreply.codeberg.org>2026-04-03 13:35:56 +0200
committerChris Boesch <chrboesch@noreply.codeberg.org>2026-04-03 13:35:56 +0200
commite0259f43a726f61da14686de802021fcdb9aacd0 (patch)
tree57359102e5e898289b91ada2d65ca742ec118c8b /exercises/102_formatting.zig
parentffde357f303e7459a12cfe4b785ae9e8ef9ebe30 (diff)
Insert space for additional async exercises
Diffstat (limited to 'exercises/102_formatting.zig')
-rw-r--r--exercises/102_formatting.zig140
1 files changed, 140 insertions, 0 deletions
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", .{});
+ }
+}