Strings
Lesson 3.3
A string is a piece of text. Lua lets you join, cut, search and format strings with a small set of tools.
Writing strings
Put text between double quotes or single quotes. Both work the same; pick one and stick to it.
local block = "Oak Planks"
local mob = 'Creeper'
print(block, mob) --> Oak Planks Creeper
Inside a string, a backslash starts an escape sequence:
| Escape | Means |
|---|---|
\n |
new line |
\t |
tab |
\" and \' |
a quote |
\\ |
a backslash |
\u{2764} |
the Unicode character with that code (here a heart) |
print("Line one\nLine two")
print("She said \"hi\"") --> She said "hi"
For text over several lines, use long brackets [[ ... ]]. Escapes don’t work inside them, which also makes them good for text full of backslashes:
local help = [[
/home go home
/spawn go to spawn]]
print(help)
/home go home
/spawn go to spawn
A line break right after the opening [[ is skipped.
Joining strings
The .. operator joins (concatenates) two strings. Numbers are converted for you:
local name = "Alex"
local level = 12
print(name .. " is level " .. level) --> Alex is level 12
Lua does not use + for strings. "a" + "b" is an error, because + tries to turn both sides into numbers.
nil can't be joined
"Hello " .. nil is an error: attempt to concatenate a nil value. When a value might be missing, wrap it in tostring(...) first, which turns nil into the text "nil".
Length
The # operator gives the length of a string in bytes:
print(#"Torch") --> 5
For plain English text, one character is one byte. Accented letters and other non-English characters take more than one byte. Use utf8.len to count characters:
print(#"Café") --> 5
print(utf8.len("Café")) --> 4
Player names and chat can contain any characters, so use utf8.len when you show or limit text length.
Strings never change
You can’t change a string in place. Every string function returns a new string, and the original stays the same:
local s = "stone"
local loud = s:upper()
print(s, loud) --> stone STONE
The string library
Every string function lives in the string table, and you can call it two ways. These lines do the same:
print(string.upper("gold")) --> GOLD
print(("gold"):upper()) --> GOLD
The second form, with a colon, is called method syntax. The lesson Classes and inheritance explains how the colon works. With a variable it reads nicely: name:upper().
The most used functions:
local s = "Diamond Sword"
print(s:upper()) --> DIAMOND SWORD
print(s:lower()) --> diamond sword
print(s:len()) --> 13
print(s:sub(1, 7)) --> Diamond
print(s:sub(9)) --> Sword
print(s:sub(-5)) --> Sword
print(s:rep(2, ", ")) --> Diamond Sword, Diamond Sword
print(s:reverse()) --> drowS dnomaiD
print(s:find("Sword")) --> 9 13
sub(i, j)cuts out the characters from positionitoj. Positions start at 1, not 0. Negative positions count from the end:-1is the last character.findgives the start and end position of the first match, ornilif there is none.rep(n, sep)repeats the stringntimes, with an optional separator.
Two more for single bytes: string.byte("A") is 65, and string.char(72, 105) is "Hi".
find, match, gmatch and gsub can also search with patterns, a small search language. The lesson String patterns covers them. Until then, two simple uses:
print(("hello world"):gsub("o", "0")) --> hell0 w0rld 2
print(("a.b.c"):find(".", 1, true)) --> 2 2
gsub replaces every match and also returns how many it replaced. In find, passing true as the fourth argument turns pattern features off, so . means a real dot.
Formatting
string.format builds a string from a template. Each % code in the template is replaced by the next argument:
print(string.format("%s has %d diamonds", "Alex", 12))
--> Alex has 12 diamonds
print(string.format("Health: %.1f", 17.25))
--> Health: 17.2
print(string.format("Pos: %d, %d, %d", 100, 64, -30))
--> Pos: 100, 64, -30
| Code | Shows |
|---|---|
%s |
any value as text |
%d |
an integer |
%f |
a float; %.2f means 2 decimals |
%x |
an integer in hexadecimal |
%5d, %-8s |
padded to 5 or 8 characters, - means left-aligned |
%03d |
padded with zeros: 007 |
%% |
a real percent sign |
%q |
a string in quotes, with escapes, safe to read back into Lua |
%d needs a whole number. string.format("%d", 2.5) is an error, but 2.0 works.
Padding lines up columns:
print(string.format("%-10s %3d", "Stone", 64))
print(string.format("%-10s %3d", "Torch", 8))
Stone 64
Torch 8
Converting
tostring(value) turns any value into a string. tonumber(text) turns a string into a number, or nil if it isn’t one. Use tonumber on anything the player types:
local input = "16"
local amount = tonumber(input)
if amount then
print("Giving " .. amount) --> Giving 16
end
Try it
Given local item = " golden apple " (two spaces on each side), print it without the spaces at the start and end, with each word starting with a capital letter: Golden Apple. Use sub, upper, and find. Hint: find the space between the words.
Show a solution
local item = " golden apple "
local trimmed = item:sub(3, -3) -- "golden apple"
local space = trimmed:find(" ") -- 7
local first = trimmed:sub(1, space - 1) -- "golden"
local second = trimmed:sub(space + 1) -- "apple"
local function capital(word)
return word:sub(1, 1):upper() .. word:sub(2)
end
print(capital(first) .. " " .. capital(second)) --> Golden Apple
This solution knows there are exactly two spaces on each side. The lesson String patterns shows a pattern that trims any amount of space in one line: item:match("^%s*(.-)%s*$").
Recap: strings are joined with .., measured with # (bytes) or utf8.len (characters), cut with sub, and built with string.format.