Back

Activity 1.3: Working with Strings

divider

The Idea

Three things about Lua strings will surprise you if you have written JavaScript or Python. You join them with .. rather than +, you measure them with # rather than a length property, and they are counted from 1.

main.lua
local first = "Ada"
local last = "Lovelace"
print(first .. " " .. last)
print(#first)
print(first:upper())
print(last:lower())
Output
Ada Lovelace
3
ADA
lovelace

Lua uses a separate operator for joining because + is reserved for arithmetic and nothing else. If you have ever been bitten by JavaScript quietly turning "16" + 1 into "161", this is the design that prevents it.

That colon

first:upper() is shorthand. Every string function really lives in a library called string, and the colon just passes the string in as the first argument. These two lines are the same line.

main.lua
local unit = "reactor"
print(string.upper(unit))
print(unit:upper())
Output
REACTOR
REACTOR

Worth filing away: the colon is not a string feature. It is a general Lua mechanism, and in Activity 1.11 you will use the same syntax to build your own objects.

Building a sentence

Chaining .. works, and numbers convert themselves along the way. It also gets ugly fast, which is what string.format is for.

main.lua
local unit = "Reactor"
local charge = 98
print(unit .. " is at " .. charge .. " percent")
print(string.format("%s is at %d%% charge", unit, charge))
Output
Reactor is at 98 percent
Reactor is at 98% charge

The placeholders are %s for a string and %d for a whole number, filled in by the arguments that follow, in order. To print an actual percent sign you write %%, since a lone % means a placeholder is coming.

Taking a string apart

sub cuts out a piece, given a start and an end position. Both ends are included, and counting starts at 1 — not 0. A negative number counts back from the end.

main.lua
local code = "SKYNEST"
print(code:sub(1, 3))
print(code:sub(-4))
print(code:sub(2, 2))
print(code:find("NEST"))
Output
SKY
NEST
K
4 7

That last line returns two values — where the match starts and where it ends. Lua functions are allowed to hand back more than one thing, which is unusual and extremely handy. Activity 1.7 covers it properly.

The 1-based counting is not a string quirk. Everything in Lua that has positions counts from 1, including tables. Getting used to it here makes Activity 1.9 much less startling.

Strings that span lines

Double square brackets hold a string exactly as you typed it, line breaks and all, with no escaping.

main.lua
local banner = [[
+------------------+
| SKYNEST v1.0 |
+------------------+]]
print(banner)
Output
+------------------+
| SKYNEST v1.0 |
+------------------+

A line break immediately after the opening [[ is skipped, which is why the banner above does not start with a blank line.

divider

Build

Start a fresh main.lua. You are building a crew badge line, the kind of thing a game would print above a character.


Task 1: Join and measure

  • Store a first name and a last name in separate variables.
  • Join them into a fullName variable with a space between.
  • Print the full name, then print its length.
main.lua
-- main.lua - Skynest crew badge
local first = "Ada"
local last = "Lovelace"
local fullName = first .. " " .. last
print(fullName)
print(#fullName)
Output
Ada Lovelace
12

Task 2: Format a status line

  • Add variables for a role and a charge percentage.
  • Use string.format to print one line containing all three.
  • Put the role in capitals, and end with a real percent sign.
main.lua
-- main.lua - Skynest crew badge
local first = "Ada"
local last = "Lovelace"
local role = "engineer"
local charge = 98
local fullName = first .. " " .. last
print(fullName)
print(#fullName)
print(string.format("%s (%s) - reactor at %d%%", fullName, role:upper(), charge))

Task 3: Generate a badge ID

  • Build a code from the first three letters of the last name, a hyphen, and the first letter of the first name.
  • Make the whole thing uppercase.
  • You can chain calls — last:sub(1, 3):upper() works, because sub hands back a string and a string has an upper.
main.lua
-- main.lua - Skynest crew badge
local first = "Ada"
local last = "Lovelace"
local role = "engineer"
local charge = 98
local fullName = first .. " " .. last
print(fullName)
print(#fullName)
print(string.format("%s (%s) - reactor at %d%%", fullName, role:upper(), charge))
local code = last:sub(1, 3):upper() .. "-" .. first:sub(1, 1):upper()
print("Badge ID:", code)

Challenge (Optional)

  • Print a boxed banner above the badge using a [[ ]] string.
  • Change the badge so it uses the last letter of the first name instead of the first. Use a negative position rather than counting the length yourself.
  • Try print(#"cafĂ©") and see whether you get what you expected. # counts bytes, and some characters take more than one.
divider

Check Your Work

Your finished file should produce this.

Output
Ada Lovelace
12
Ada Lovelace (ENGINEER) - reactor at 98%
Badge ID: LOV-A

If your badge came out as LOV-A without you counting a single character by hand, you have the idea. If it came out one letter short or long, you have met the 1-based counting for real, which is a better way to learn it than being told.