aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/exercises/099_formatting.zig
blob: 4b64209784d5aed9b7ded2903806ff0dac7b6b39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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://github.com/ziglang/zig/blob/master/lib/std/fmt.zig#L29
//
// 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-{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", .{});
    }
}