String Basics (.. / #)
In Lua, strings are immutable values. There are three kinds of string literals: single-quoted, double-quoted, and long strings ([[]]). Strings are concatenated with the .. operator, and their byte length is obtained with the # operator.
Syntax
-- ----------------------------------------------- -- String literal forms -- ----------------------------------------------- local s1 = "Double-quoted string" local s2 = 'Single-quoted string' -- identical behavior to double-quoted local s3 = [[ Long string Multiple lines can be written as-is ]] -- [[ ]] for multi-line literals -- ----------------------------------------------- -- String concatenation (.. operator) -- ----------------------------------------------- local result = "Terry" .. " " .. "Bogard" -- .. joins strings -- ----------------------------------------------- -- String length (# operator) -- ----------------------------------------------- local len = #result -- returns byte count (not character count for multibyte text) -- ----------------------------------------------- -- Escape sequences -- ----------------------------------------------- local esc = "newline\n\ttab\t backslash\\" -- \n newline, \t tab, \\ backslash
Syntax Reference
| Operator / Notation | Description |
|---|---|
"..." / '...' | String literals. Double-quoted and single-quoted forms are interchangeable. |
[[...]] | Long string literal. Allows multi-line text containing newlines without escape sequences. |
.. (two dots) | String concatenation operator. Returns a new string that is the concatenation of both operands. |
# (hash) | String length operator. Returns the byte count of the string. For multibyte UTF-8 characters, byte count and character count differ. |
\n | Escape sequence: line feed (newline). |
\t | Escape sequence: horizontal tab. |
\\ | Escape sequence: a single backslash character. |
\" / \' | Escape sequence: embeds a double or single quote inside a string literal. |
\NNN (decimal) | Escape sequence: the character whose byte value equals the decimal number (e.g. \65 → A). |
Sample Code
kof_string_basic.lua
-- kof_string_basic.lua — string basics sample
-- Uses KOF (The King of Fighters) characters to demonstrate
-- literals, concatenation (..), length (#), and escape sequences
-- -----------------------------------------------
-- Three kinds of string literals
-- -----------------------------------------------
-- Double-quoted literal
local name1 = "Terry Bogard"
-- Single-quoted literal (identical to double-quoted)
local name2 = 'Andy Bogard'
-- Long string literal ([[ ]] for multi-line, no escaping needed)
local profile = [[
Name: Mai Shiranui
Team: Fatal Fury Team
Special move: Ryuenbu
]]
print("=== String Literals ===")
print(name1)
print(name2)
print(profile)
-- -----------------------------------------------
-- String concatenation with .. operator
-- -----------------------------------------------
print("=== Concatenation (.. operator) ===")
-- Multiple strings joined with ..
local fighter = "Joe " .. "Higashi"
print(fighter)
-- Numbers are automatically converted to strings when used with ..
local power = 92
local info = "Ralf Jones power level: " .. power
print(info)
-- Building a longer string with local variables improves readability
local team = "Fatal Fury Team"
local member = name1 .. ", " .. name2 .. ", Mai Shiranui"
local line = "[" .. team .. "] " .. member
print(line)
print("")
-- -----------------------------------------------
-- String length (byte count) with # operator
-- -----------------------------------------------
print("=== String Length (# operator) ===")
local ascii_name = "Terry Bogard"
print(ascii_name .. " byte count: " .. #ascii_name) -- ASCII: 1 char = 1 byte
-- Japanese (UTF-8): 1 character = 3 bytes, so byte count != character count
local jp_name = "テリー・ボガード"
print(jp_name .. " byte count: " .. #jp_name) -- 8 chars x 3 bytes = 24
-- Empty string has length 0
local empty = ""
print("Empty string byte count: " .. #empty)
print("")
-- -----------------------------------------------
-- Escape sequences
-- -----------------------------------------------
print("=== Escape Sequences ===")
-- \n inserts a newline, \t inserts a tab
local escape_demo = "Special moves:\n\tPower Geyser\n\tTriangle Geyser\n\tPower Dunk"
print(escape_demo)
print("")
-- \\ outputs a literal backslash
local path = "C:\\KOF\\fighters\\terry.lua"
print("File path: " .. path)
print("")
-- \" embeds a double quote inside a double-quoted string
local quote = 'Terry\'s line: "OK, let\'s go!"'
print(quote)
print("")
-- \65 specifies a character by its decimal byte value (65 = 'A')
local byte_demo = "\84\101\114\114\121" -- T=84, e=101, r=114, r=114, y=121
print("String from byte values: " .. byte_demo)
lua kof_string_basic.lua === String Literals === Terry Bogard Andy Bogard Name: Mai Shiranui Team: Fatal Fury Team Special move: Ryuenbu === Concatenation (.. operator) === Joe Higashi Ralf Jones power level: 92 [Fatal Fury Team] Terry Bogard, Andy Bogard, Mai Shiranui === String Length (# operator) === Terry Bogard byte count: 12 テリー・ボガード byte count: 24 Empty string byte count: 0 === Escape Sequences === Special moves: Power Geyser Triangle Geyser Power Dunk File path: C:\KOF\fighters\terry.lua Terry's line: "OK, let's go!" String from byte values: Terry
Common Mistakes
Concatenating a numeric literal directly with .. causes an error
Placing .. immediately after a numeric literal without a space causes Lua to interpret it as ... (varargs), resulting in a syntax error. Always put a space between the number and .., or use tostring() to convert explicitly.
-- NG: no space between a numeric literal and .. causes a syntax error -- print(42 .." item")
-- OK: add a space or use tostring() print(42 .. " item") -- space between number and .. print(tostring(42) .. " item") -- explicit conversion with tostring()
The # operator returns byte count, not character count, for multibyte strings
The # operator returns the byte count of a string. For ASCII text, byte count equals character count, but UTF-8 Japanese characters are 3 bytes each, so the result differs from the character count. Use utf8.len() (Lua 5.3 and later) to count characters.
-- NG: # returns byte count, not character count, for Japanese text local name = "Yagami Iori" -- ASCII: byte count equals character count local jpname = "八神庵" print(#jpname) -- 9 (3 chars x 3 bytes; not the character count)
-- OK: use utf8.len() to get the character (code point) count (Lua 5.3+) local jpname = "八神庵" print(utf8.len(jpname)) -- 3 (character count) print(#jpname) -- 9 (byte count)
Using == for string comparison (this is correct in Lua)
Developers coming from C often look for a strcmp() equivalent. In Lua, == compares string content directly. There is no strcmp function, and none is needed.
-- NG: strcmp does not exist in Lua -- if strcmp(name, "Yagami Iori") == 0 then ...
-- OK: use == to compare string contents
local name = "Yagami Iori"
if name == "Yagami Iori" then
print("match")
end
Overview
Lua strings are immutable values expressed with three kinds of literals: double-quoted, single-quoted, and long strings ([[]]). The .. (two dots) operator concatenates the left and right operands and returns a new string. When a number is used with .., it is automatically converted to a string. The # operator returns the byte count of a string. For ASCII text, byte count matches character count, but UTF-8 Japanese characters are typically 3 bytes each, so # returns byte count, not character count. To handle character counts accurately, use utf8.len() (Lua 5.3 and later), described in the string methods page. Escape sequences include \n (newline), \t (tab), \\ (backslash), and \NNN (decimal byte value).
If you find any errors or copyright issues, please contact us.