099_formatting.zig 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //
  2. // Terminals have come a long way over the years. Starting with
  3. // monochrome lines on flickering CRT monitors and continuously
  4. // improving to today's modern terminal emulators with sharp
  5. // images, true color, fonts, ligatures, and characters in every
  6. // known language.
  7. //
  8. // Formatting our results to be appealing and allow quick visual
  9. // comprehension of the information is what users desire. <3
  10. //
  11. // C set string formatting standards over the years, and Zig is
  12. // following suit and growing daily. Due to this growth, there is
  13. // no official documentation for standard library features such
  14. // as string formatting.
  15. //
  16. // Therefore, the comments for the format() function are the only
  17. // way to definitively learn how to format strings in Zig:
  18. //
  19. // https://github.com/ziglang/zig/blob/master/lib/std/fmt.zig#L33
  20. //
  21. // Zig already has a very nice selection of formatting options.
  22. // These can be used in different ways, but generally to convert
  23. // numerical values into various text representations. The results
  24. // can be used for direct output to a terminal or stored for
  25. // later use or written to a file. The latter is useful when
  26. // large amounts of data are to be processed by other programs.
  27. //
  28. // In Ziglings, we are concerned with the output to the console.
  29. // But since the formatting instructions for files are the same,
  30. // what you learn applies universally.
  31. //
  32. // Since we write to "debug" output in Ziglings, our answers
  33. // usually look something like this:
  34. //
  35. // print("Text {placeholder} another text \n", .{foo});
  36. //
  37. // In addition to being replaced with foo in this example, the
  38. // {placeholder} in the string can also have formatting applied.
  39. // How does that work?
  40. //
  41. // This actually happens in several stages. In one stage, escape
  42. // sequences are evaluated. The one we've seen the most
  43. // (including the example above) is "\n" which means "line feed".
  44. // Whenever this statement is found, a new line is started in the
  45. // output. Escape sequences can also be written one after the
  46. // other, e.g. "\n\n" will cause two line feeds.
  47. //
  48. // By the way, the result of these escape sequences is passed
  49. // directly to the terminal program. Other than translating them
  50. // into control codes, escape sequences have nothing to do with
  51. // Zig. Zig knows nothing about "line feeds" or "tabs" or
  52. // "bells".
  53. //
  54. // The formatting that Zig *does* perform itself is found in the
  55. // curly brackets: "{placeholder}". Formatting instructions in
  56. // the placeholder will determine how the corresponding value,
  57. // e.g. foo, is displayed.
  58. //
  59. // And this is where it gets exciting, because format() accepts a
  60. // variety of formatting instructions. It's basically a tiny
  61. // language of its own. Here's a numeric example:
  62. //
  63. // print("Catch-{x:0>4}.", .{twenty_two});
  64. //
  65. // This formatting instruction outputs a hexadecimal number with
  66. // leading zeros:
  67. //
  68. // Catch-0x0016.
  69. //
  70. // Or you can center-align a string like so:
  71. //
  72. // print("{s:*^20}\n", .{"Hello!"});
  73. //
  74. // Output:
  75. //
  76. // *******Hello!*******
  77. //
  78. // Let's try making use of some formatting. We've decided that
  79. // the one thing missing from our lives is a multiplication table
  80. // for all numbers from 1-15. We want the table to be nice and
  81. // neat, with numbers in straight columns like so:
  82. //
  83. // X | 1 2 3 4 5 ...
  84. // ---+---+---+---+---+---+
  85. // 1 | 1 2 3 4 5
  86. //
  87. // 2 | 2 4 6 8 10
  88. //
  89. // 3 | 3 6 9 12 15
  90. //
  91. // 4 | 4 8 12 16 20
  92. //
  93. // 5 | 5 10 15 20 25
  94. //
  95. // ...
  96. //
  97. // Without string formatting, this would be a more challenging
  98. // assignment because the number of digits in the numbers varies
  99. // from 1 to 3. But formatting can help us with that.
  100. //
  101. const std = @import("std");
  102. const print = std.debug.print;
  103. pub fn main() !void {
  104. // Max number to multiply
  105. const size = 15;
  106. // Print the header:
  107. //
  108. // We start with a single 'X' for the diagonal.
  109. print("\n X |", .{});
  110. // Header row with all numbers from 1 to size.
  111. for (0..size) |n| {
  112. print("{d:>3} ", .{n + 1});
  113. }
  114. print("\n", .{});
  115. // Header column rule line.
  116. var n: u8 = 0;
  117. while (n <= size) : (n += 1) {
  118. print("---+", .{});
  119. }
  120. print("\n", .{});
  121. // Now the actual table. (Is there anything more beautiful
  122. // than a well-formatted table?)
  123. for (0..size) |a| {
  124. print("{d:>2} |", .{a + 1});
  125. for (0..size) |b| {
  126. // What formatting is needed here to make our columns
  127. // nice and straight?
  128. print("{???} ", .{(a + 1) * (b + 1)});
  129. }
  130. // After each row we use double line feed:
  131. print("\n\n", .{});
  132. }
  133. }