Step 1 of 5 · Reading · ~3 min
Learn
Strings
String Formatting
string.format is Lua's answer to "print this number with exactly two decimals". You give it a template full of % placeholders plus the values to drop in, and it returns a string. The specifiers come straight from C's printf, so they will look familiar if you have met them anywhere else.
print(string.format("%d items", 3))
print(string.format("%.2f", 1.5))
print(string.format("%s scored %d", "Ada", 95))
--> 3 items
--> 1.50
--> Ada scored 95
The middle line is the whole reason this function exists. Plain print(1.5) gives 1.5; %.2f gives 1.50. Money, percentages and report columns all need the trailing zero that ordinary printing throws away.
The specifiers worth knowing
| Specifier | Takes | Example | Result |
|---|---|---|---|
%d | an integer | ("%d", 42) | 42 |
%f | a number | ("%f", 1.5) | 1.500000 |
%.2f | a number | ("%.2f", 1.5) | 1.50 |
%s | anything | ("%s", true) | true |
%x | an integer | ("%x", 255) | ff |
%q | a string | ("%q", 'a"b') | "a\"b" |
%% | nothing | ("100%%") | 100% |
%s is the forgiving one: it calls tostring on whatever arrives, so a boolean, a table or a nil all format without complaint. That makes it ideal for debugging and wrong for money.
Width and alignment
A number between the % and the letter sets a minimum width. A minus sign left-aligns instead of right-aligning.
print(string.format("[%5d]", 42))
print(string.format("[%-5d]", 42))
print(string.format("[%8.2f]", 3.14159))
print(string.format("[%-8s]", "ok"))
--> [ 42]
--> [42 ]
--> [ 3.14]
--> [ok ]
This is how you line up columns without counting spaces by hand.
The trap: %d refuses real floats
%d demands a value that has an exact integer representation. A float like 3.0 qualifies. A float like 2.5 does not — and it is a hard error, not a silent rounding.
✗ float into %d
print(string.format("%d", 2.5))
--> bad argument #2 to 'string.format' (number has no integer representation)
✓ convert first, or use a float specifier
print(string.format("%d", math.floor(2.5)))
print(string.format("%.2f", 2.5))
--> 2
--> 2.50
This bites because tonumber decides the subtype from the text: tonumber("3") is an integer and formats happily with %d, while tonumber("3.0") is a float that happens to survive and tonumber("3.5") is a float that does not.
Literal symbols in the template
Everything in the template that is not a % placeholder is copied through untouched, so currency symbols and punctuation need no escaping. Only the percent sign itself does, written twice.
print(string.format("total: $%.2f (%d%% off)", 12.5, 20))
--> total: $12.50 (20% off)
Your exercise
Format Receipt reads three lines — a product name, a quantity, a price — and prints one line shaped <name>: <qty> @ $<price> = $<total>, where the total is quantity times price and both money amounts carry exactly two decimals.
The starter reads all three values and leaves the format string as a comment for you to finish.
Two mistakes the grader will catch. Handing the price to %d aborts the whole run with number has no integer representation, because tonumber("0.50") is a float. And formatting the total with %s, or building the line with .., prints 1.5 where the test demands 1.50 — those forms show you the number Lua stores, not the number a receipt needs.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…