Luawe the Wayfarer Engine's scripting language All pages

Working with text

Strings are for names, messages and anything a text in the level should say. This page shows how to take them apart, put them together and search them.

The everyday tools

Every string has the functions of the string library as its own, called with a colon:

local name = "Pathfinder"

print(#name)
print(name:upper(), name:lower())
print(name:sub(1, 4))  -- from place 1 to place 4
print(name:sub(-6))    -- a place below 0 counts from the end
print(name:rep(2, " "))
print(name:reverse())

It prints

10
PATHFINDER pathfinder
Path
finder
Pathfinder Pathfinder
rednifhtaP

name:upper() is the same as string.upper(name). A string never changes: each of these gives a new string, and name stays as it was.

A string written out needs brackets round it before the colon: ("abc"):upper().

Putting text together

.. joins. In a backtick string, {...} puts a value in. string.format gives the most control over how a number looks:

local seconds = 83.456

print("Time: " .. seconds)
print(`Time: {math.round(seconds, 1)} s`)
print(string.format("Time: %.1f s", seconds))
print(string.format("%d:%02d", seconds // 60, math.floor(seconds % 60)))

It prints

Time: 83.456
Time: 83.5 s
Time: 83.5 s
1:23

The codes string.format knows:

CodeShowsExample
%dA whole number (round it first: %d refuses 2.5)%d of 42 is 42
%.2fA number with that many decimals%.2f of 3.14159 is 3.14
%sAny value, as text%s of true is true
%5d %5sPadded with spaces to 5 wide, at the right%5s of "ab" is three spaces and ab
%-5sThe same, padded at the left
%05dPadded with zeros%05d of 42 is 00042
%xA whole number in base 16%x of 255 is ff
%%A percent sign

table.concat joins a whole list, with something between the pieces:

print(table.concat({ "red", "green", "blue" }, " and "))

It prints

red and green and blue

Cutting text up

local line = "  saw, block ,spike  "

local parts = string.split(line, ",")
for i, part in parts do
    parts[i] = string.trim(part) -- without the spaces at its ends
end
print(table.concat(parts, "|"))

print(table.concat(string.split("abc", ""), "-")) -- "" cuts it into letters

It prints

saw|block|spike
a-b-c

Finding text

find says where something is in a string: where it starts and where it ends, or nil when it is not there.

local text = "the red door"

print(text:find("red"))
print(text:find("blue"))

if text:find("door") then
    print("it mentions a door")
end

It prints

5 7
nil
it mentions a door

Patterns

find, match, gmatch and gsub do not only look for exact text. They look for a pattern: a description of what the text should look like. In a pattern, % followed by a letter stands for a kind of character:

WrittenStands for
%dA digit
%aA letter (a to z, A to Z)
%wA letter or a digit
%sA space, a tab or a line break
%l %uA small letter, a capital letter
%pA punctuation sign
.Any character at all
[abc]One of these; [a-f] one from a to f; [^abc] any but these

The capital of a letter means the opposite: %D is anything but a digit.

After any of them, a sign says how many:

SignMeans
+One or more, as many as possible
*None or more, as many as possible
-None or more, as few as possible
?One or none

^ at the start of a pattern means "at the start of the text", $ at its end means "at the end of the text".

Brackets catch what matched inside them, and that is what match gives back:

print(("level 12"):match("%d+"))
print(("width=30"):match("(%a+)=(%d+)"))
print(("  padded  "):match("^%s*(.-)%s*$") .. "|")
print(("hello"):match("%d+"))

It prints

12
width 30
padded|
nil

gmatch goes through every match, in a for loop:

for word in ("stay on the floor"):gmatch("%a+") do
    print(word)
end

It prints

stay
on
the
floor

gsub replaces every match and gives the new string (and, after it, how many it replaced). The replacement can be text, where %1 stands for what the first pair of brackets caught, or a function that is given the match and returns what to put there:

print((("3 coins, 12 gems"):gsub("%d+", "many")))
print((("door:open"):gsub("(%a+):(%a+)", "%2 %1")))
print((("3 coins, 12 gems"):gsub("%d+", function(n)
    return tonumber(n) * 2
end)))

It prints

many coins, many gems
open door
6 coins, 24 gems

(The extra brackets round each call keep only the first of the two values gsub gives.)

The signs ( ) . % + - * ? [ ] ^ $ have a meaning in a pattern. To look for one of them as itself, put % before it (%. is a real full stop), or tell find to take the text literally with true as its fourth value:

print(("3.14"):find(".", 1, true))
print(("3.14"):find("%."))

It prints

2 2
2 2

Letters of every language

A string is kept as bytes, and the letters of many languages take more than one byte each. # and sub count bytes, which is right for plain English text and wrong for most others. The utf8 library counts letters:

local word = "héllo"
print(#word, utf8.len(word))
print(utf8.sub(word, 1, 2))

It prints

6 5
hé

Names of variables can be written in any language's letters, too.

Next: when something goes wrong.