String Basics: Concat and Length
Use .. for concatenation, # for length, and string.rep/reverse.
String Basics: Concat and Length is a free Lua Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
String Concatenation with ..
Lua uses .. (two dots) for string concatenation. It works with strings and numbers (numbers are converted automatically). Unlike + in many languages, + in Lua is arithmetic only — using + on strings causes an error.
local first = "Hello"
local second = "World"
print(first .. ", " .. second .. "!") -- Hello, World!
-- Numbers auto-converted
local age = 30
print("Age: " .. age) -- Age: 30
-- Bad: print("x" + "y") ERROR: arithmetic on stringLength Operator #
The # operator returns the byte length of a string. For ASCII strings, this equals the character count. For multi-byte UTF-8 strings, # counts bytes, not characters — a UTF-8 emoji counts as 4. Use a UTF-8 library for character-accurate lengths.
print(#"hello") -- 5
print(#"") -- 0
print(#"café") -- 5 (c,a,f,é=2bytes)
local s = "Lua"
for i = 1, #s do
io.write(string.byte(s, i) .. " ")
end
print() -- 76 117 97string.rep and string.reverse
string.rep(s, n, sep) repeats string s exactly n times with optional separator. string.reverse(s) reverses the byte order of the string. Both return new strings — Lua strings are immutable.
print(string.rep("ab", 3)) -- ababab
print(string.rep("ha", 3, "-")) -- ha-ha-ha
print(string.rep("x", 0)) -- (empty)
print(string.reverse("hello")) -- olleh
print(string.reverse("12345")) -- 54321string.upper and string.lower
string.upper(s) and string.lower(s) convert ASCII characters. They don't handle Unicode — non-ASCII characters pass through unchanged. For case-insensitive comparison, convert both strings to lower before comparing.
print(string.upper("hello")) -- HELLO
print(string.lower("WORLD")) -- world
print(string.upper("Lua 5.4!")) -- LUA 5.4!
-- Case-insensitive comparison
local a = "Hello"
local b = "hello"
print(a:lower() == b:lower()) -- trueColon Method Syntax
String functions can be called using colon syntax on string values: s:upper() instead of string.upper(s). This works because strings have a metatable with __index = string, so all string library functions are accessible as methods on any string.
local s = " hello world "
print(s:upper()) -- HELLO WORLD
print(s:len()) -- 15
print(s:rep(2, "|")) -- same as string.rep(s,2,"|")
-- Chain calls
print(("lua"):upper():reverse()) -- AULString Immutability
Lua strings are immutable. You cannot modify characters in-place. Every string operation creates a new string. For heavy concatenation inside loops, use a table to accumulate parts and table.concat at the end — much more efficient than repeated ...
-- Efficient string building
local parts = {}
for i = 1, 5 do
parts[i] = "item" .. i
end
local result = table.concat(parts, ", ")
print(result) -- item1, item2, item3, item4, item5
-- Slow! Creates 5 intermediate strings:
-- local s = ""
-- for i = 1, 5 do s = s .. "item" .. i endtable.concat for Joining
table.concat(t, sep, i, j) joins array elements into a string with a separator. It only works with string and number values — tables or booleans cause an error. This is the fastest way to build strings from many parts.
local parts = {"one", "two", "three", "four"}
print(table.concat(parts, ", ")) -- one, two, three, four
print(table.concat(parts, " | ", 2, 3)) -- two | three
-- Building CSV
local row = {1, "Alice", 95, true}
-- Need tostring for non-string values:
for i, v in ipairs(row) do row[i] = tostring(v) end
print(table.concat(row, ","))String Comparison
Strings are compared lexicographically by byte value. Uppercase letters come before lowercase in ASCII (A=65, a=97), so "Z" < "a" is true. Use string.lower on both sides for case-insensitive ordering.
print("abc" < "abd") -- true
print("abc" < "abcd") -- true (shorter)
print("Z" < "a") -- true (Z=90, a=97)
print("10" < "9") -- true (lexicographic!)
print(10 < 9) -- false (numeric)
-- Sort strings case-insensitively
local words = {"Banana","apple","Cherry"}
table.sort(words, function(a,b) return a:lower()<b:lower() end)
print(table.concat(words,", "))tostring and tonumber
tostring(v) converts any value to its string representation. tonumber(s, base) parses a string to a number. tonumber returns nil if parsing fails, unlike many languages that throw an exception. Base can be 2-36 for integer parsing.
print(tostring(42)) -- 42
print(tostring(true)) -- true
print(tostring(nil)) -- nil
print(tostring({1,2})) -- table: 0x...
print(tonumber("3.14")) -- 3.14
print(tonumber("0xff")) -- 255 (hex)
print(tonumber("11",2)) -- 3 (binary)
print(tonumber("abc")) -- nil (invalid)String Interning
Lua interns short strings: identical string content shares the same object in memory. This makes == on strings effectively a pointer comparison after a hash check — very fast. Interning also means string creation has a small overhead (hash computation), but repeated strings are free.
local s1 = "hello"
local s2 = "hel" .. "lo"
-- Same content, interned to same object
print(s1 == s2) -- true
print(#s1) -- 5
-- Long strings may not be interned
-- They are still compared correctly by value
local long1 = string.rep("x", 1000)
local long2 = string.rep("x", 1000)
print(long1 == long2) -- trueQuick Check
What is the most efficient way to build a long string from many small parts in Lua?
Recap: String Basics
Key points:
..concatenates; never use+for strings#scounts bytes (not Unicode chars)s:upper(),s:lower(),s:rep(n, sep),s:reverse()- Strings are immutable — every op returns a new string
- Build large strings with table +
table.concat tostring/tonumberfor type conversion
Frequently asked questions
Is the “String Basics: Concat and Length” lesson free?
Yes — the full text of “String Basics: Concat and Length” is free to read here on the web, and the Lua Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Lua Academy course, upgrade to CoddyKit PRO.
What will I learn in “String Basics: Concat and Length”?
Use .. for concatenation, # for length, and string.rep/reverse. You practise Lua Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Lua Academy?
No prior experience is required. Lua Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “String Basics: Concat and Length” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Lua Academy lesson?
Yes. Every Lua Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- String Basics: Concat and Length
- Finding and Extracting Substrings
- string.format for Output
- string.gsub and string.gmatch