string.format()
Lua's string.format() generates a string using format specifiers similar to C's printf(). It is useful when precise control over output format is needed, such as aligning numbers, specifying decimal places, or setting string widths.
Syntax
-- -----------------------------------------------
-- Basic syntax of string.format()
-- -----------------------------------------------
string.format(formatstr, ...)
-- formatstr : format string containing % specifiers
-- ... : values corresponding to each specifier (variadic)
-- returns : the formatted string
-- -----------------------------------------------
-- Format specifier structure
-- -----------------------------------------------
-- %[flags][width][.precision]conversion
-- flags : - (left-align) + (force sign) 0 (zero-pad) space (space for sign)
-- width : minimum output width (number)
-- .precision : decimal places for %f/%e, or max chars for %s
-- conversion : d / i / u / f / e / g / s / q / x / X / o / c / %
-- -----------------------------------------------
-- Method call style (: operator)
-- -----------------------------------------------
("format string"):format(...)
-- String library functions can also be called as methods via the metatable
Format Specifier Reference
| Specifier | Description |
|---|---|
%d / %i | Outputs a signed integer (decimal). |
%u | Outputs an unsigned integer (decimal). |
%f | Outputs a floating-point number in decimal notation. Default is 6 decimal places. |
%e / %E | Outputs a floating-point number in scientific notation. %E uses an uppercase E. |
%g / %G | Automatically chooses the shorter of %f and %e representations. |
%s | Outputs a string. A precision value limits the maximum number of characters. |
%q | Outputs a string in a form that can be re-read as Lua code (double-quoted, with special characters escaped). |
%x / %X | Outputs an integer as hexadecimal. %X uses uppercase letters. |
%o | Outputs an integer as octal. |
%c | Outputs the character corresponding to the given ASCII code. |
%% | Outputs a literal % sign. |
%5d (width) | Sets minimum width to 5, right-aligned; pads with spaces on the left if fewer than 5 digits. |
%-5d (left-align) | The - flag left-aligns the value, padding with spaces on the right. |
%05d (zero-pad) | The 0 flag pads with zeros on the left. |
%.2f (precision) | Outputs the floating-point number with 2 decimal places. |
%8.2f (width + precision) | Outputs the floating-point number with minimum width 8 and 2 decimal places. |
Sample Code
dragonball_format.lua
-- dragonball_format.lua — string.format() specifier sample
-- Uses Dragon Ball characters to demonstrate each format specifier
-- -----------------------------------------------
-- %d : signed integer (decimal)
-- -----------------------------------------------
local goku_power = 9000
local vegeta_power = 8500
local gohan_power = 7800
local piccolo_power = 6200
local frieza_power = 12000
print("=== %d : integer output ===")
print(string.format("Son Goku power level: %d", goku_power))
print(string.format("Vegeta power level: %d", vegeta_power))
print("")
-- -----------------------------------------------
-- %5d, %-5d, %05d : width, left-align, zero-pad
-- -----------------------------------------------
print("=== width / left-align / zero-pad ===")
-- %6d : min width 6, right-aligned (default)
-- %-6d : min width 6, left-aligned
-- %06d : min width 6, zero-padded right-aligned
local fighters = {
{ name = "Son Goku", power = goku_power },
{ name = "Vegeta", power = vegeta_power },
{ name = "Son Gohan", power = gohan_power },
{ name = "Piccolo", power = piccolo_power },
{ name = "Frieza", power = frieza_power },
}
print(string.format("%-12s %6s %-6s %s", "Name", "Right", "Left", "ZeroPad"))
print(string.rep("-", 44))
for _, f in ipairs(fighters) do
print(string.format("%-12s %6d %-6d %06d",
f.name, f.power, f.power, f.power))
end
print("")
-- -----------------------------------------------
-- %f, %.2f, %8.2f : floating-point numbers
-- -----------------------------------------------
print("=== %f : floating-point ===")
local goku_height = 1.75
local vegeta_height = 1.64
local gohan_height = 1.76
-- Default outputs 6 decimal places
print(string.format("Son Goku height (default): %f m", goku_height))
-- .2f limits to 2 decimal places
print(string.format("Son Goku height (2 places): %.2f m", goku_height))
-- width 8, 2 decimal places, right-aligned
print(string.format("%-12s %8.2f m", "Son Goku", goku_height))
print(string.format("%-12s %8.2f m", "Vegeta", vegeta_height))
print(string.format("%-12s %8.2f m", "Son Gohan", gohan_height))
print("")
-- -----------------------------------------------
-- %e : scientific notation
-- -----------------------------------------------
print("=== %e : scientific notation ===")
local universe_power = 99999999999.0
print(string.format("Universal power: %e", universe_power))
print(string.format("Universal power: %.3e", universe_power)) -- 3 decimal places
print(string.format("Universal power: %E", universe_power)) -- uppercase E
print("")
-- -----------------------------------------------
-- %s : string / %.5s : max characters
-- -----------------------------------------------
print("=== %s : string ===")
local kamehameha = "Kamehameha"
local final_flash = "Final Flash"
print(string.format("Son Goku's technique: %s", kamehameha))
print(string.format("Vegeta's technique: %s", final_flash))
-- %-15s : min width 15, left-aligned
print("")
print(string.format("%-12s %-20s", "User", "Technique"))
print(string.rep("-", 34))
print(string.format("%-12s %-20s", "Son Goku", kamehameha))
print(string.format("%-12s %-20s", "Vegeta", final_flash))
print(string.format("%-12s %-20s", "Son Gohan", "Kamehameha (learned from father)"))
print(string.format("%-12s %-20s", "Piccolo", "Special Beam Cannon"))
print("")
-- -----------------------------------------------
-- %q : re-readable string form
-- -----------------------------------------------
print("=== %q : escaped string ===")
local quote = 'Frieza: "My power level is 530,000."'
-- %q wraps in double quotes and auto-escapes special characters
print(string.format("Normal : %s", quote))
print(string.format("%%q form: %q", quote))
print("")
-- -----------------------------------------------
-- %x, %X, %o : hexadecimal and octal
-- -----------------------------------------------
print("=== %x / %X / %o : base conversion ===")
local scouter = 8500
print(string.format("Scouter reading (decimal): %d", scouter))
print(string.format("Scouter reading (hex): %x", scouter))
print(string.format("Scouter reading (HEX): %X", scouter))
print(string.format("Scouter reading (octal): %o", scouter))
print(string.format("Hex zero-padded (6 digits): %06x", scouter))
print("")
-- -----------------------------------------------
-- %c : character code to character
-- -----------------------------------------------
print("=== %c : character code ===")
print(string.format("ASCII 65 = %c", 65)) -- A
print(string.format("ASCII 90 = %c", 90)) -- Z
print(string.format("ASCII 97 = %c", 97)) -- a
print("")
-- -----------------------------------------------
-- %% : literal percent sign
-- -----------------------------------------------
print("=== %% : percent sign ===")
local zenkai_rate = 200
print(string.format("Full power: %d%%", zenkai_rate)) -- %% outputs %
print("")
-- -----------------------------------------------
-- Combined example: power level ranking
-- -----------------------------------------------
print("=== Overall Ranking ===")
print(string.format("%-4s %-12s %8s %s", "Rank", "Name", "Power", "Note"))
print(string.rep("=", 40))
local ranking = {
{ rank = 1, name = "Frieza", power = 12000, note = "Full transformation" },
{ rank = 2, name = "Son Goku", power = 9000, note = "Kaio-ken active" },
{ rank = 3, name = "Vegeta", power = 8500, note = "Elite warrior" },
{ rank = 4, name = "Son Gohan", power = 7800, note = "Hidden potential" },
{ rank = 5, name = "Piccolo", power = 6200, note = "Namekian" },
}
for _, r in ipairs(ranking) do
print(string.format("%2d. %-12s %8d %s",
r.rank, r.name, r.power, r.note))
end
lua dragonball_format.lua === %d : integer output === Son Goku power level: 9000 Vegeta power level: 8500 === width / left-align / zero-pad === Name Right Left ZeroPad -------------------------------------------- Son Goku 9000 9000 009000 Vegeta 8500 8500 008500 Son Gohan 7800 7800 007800 Piccolo 6200 6200 006200 Frieza 12000 12000 012000 === %f : floating-point === Son Goku height (default): 1.750000 m Son Goku height (2 places): 1.75 m Son Goku 1.75 m Vegeta 1.64 m Son Gohan 1.76 m === %e : scientific notation === Universal power: 1.000000e+11 Universal power: 1.000e+11 Universal power: 1.000000E+11 === %s : string === Son Goku's technique: Kamehameha Vegeta's technique: Final Flash User Technique ---------------------------------- Son Goku Kamehameha Vegeta Final Flash Son Gohan Kamehameha (learned from father) Piccolo Special Beam Cannon === %q : escaped string === Normal : Frieza: "My power level is 530,000." %q form: "Frieza: \"My power level is 530,000.\"" === %x / %X / %o : base conversion === Scouter reading (decimal): 8500 Scouter reading (hex): 2134 Scouter reading (HEX): 2134 Scouter reading (octal): 20464 Hex zero-padded (6 digits): 002134 === %c : character code === ASCII 65 = A ASCII 90 = Z ASCII 97 = a === %% : percent sign === Full power: 200% === Overall Ranking === Rank Name Power Note ======================================== 1. Frieza 12000 Full transformation 2. Son Goku 9000 Kaio-ken active 3. Vegeta 8500 Elite warrior 4. Son Gohan 7800 Hidden potential 5. Piccolo 6200 Namekian
Common Mistakes
Passing a floating-point number to %d
%d is for integers. Passing a floating-point number truncates the fractional part. Use %f or %g when outputting floating-point values.
-- NG: passing a float to %d drops the decimal part
local height = 1.75
print(string.format("Height: %d m", height)) -- "Height: 1 m" (decimal lost)
-- OK: use %f or %g for floating-point values
local height = 1.75
print(string.format("Height: %.2f m", height)) -- "Height: 1.75 m"
print(string.format("Height: %g m", height)) -- "Height: 1.75 m" (trailing zeros omitted)
Passing nil to %s causes an error
Passing nil to %s raises an error. To output nil as a string, convert it first with tostring(nil).
-- NG: passing nil to %s causes an error
local value = nil
-- print(string.format("Value: %s", value)) -- error: bad argument #2 to 'format'
-- OK: convert with tostring() first
local value = nil
print(string.format("Value: %s", tostring(value))) -- "Value: nil"
Forgetting zero-padding and ending up with uneven column widths
When displaying timestamps, rankings, or other fixed-width numbers, omitting the zero-pad specifier results in uneven output. Use %02d and similar specifiers to enforce a consistent width.
-- NG: %d alone does not pad, so single-digit values are narrower
print(string.format("Time: %d:%d", 9, 5)) -- "Time: 9:5" (no zero-padding)
-- OK: use %02d to enforce two-digit zero-padded output
print(string.format("Time: %02d:%02d", 9, 5)) -- "Time: 09:05"
Overview
string.format() is a format function derived from C's printf(). It replaces the % specifiers in the first argument with subsequent arguments and returns the resulting string. Use %d for integers, %f or %e for floating-point numbers, and %s for strings. Combining minimum width, precision, and flags enables fine-grained control such as column alignment and zero-padding. %q escapes a string so it can be re-read as Lua source, making it useful for data serialization. Because Lua strings have a metatable, ("format"):format(...) is an equivalent method-call style alternative to string.format(...). Also see the string methods reference.
If you find any errors or copyright issues, please contact us.