The string data type is a sequence of characters, such as letters, numbers, and symbols. It's the data type for storing most text-based information.
Declaring Strings
To declare a string variable, put quotes around the characters. It's more common to use double quotes ("), but single quotes (') also work. If you want to include a single or double quote in your string, wrap your string around the other type of quote, or use an escaped quote.
local string1 = "Hello world!"print(string1) --> Hello world!local string2 = 'Hello "world"!'print(string2) --> Hello "world"!
To include both single and double quotes in a string, or to create multi-line strings, declare them using double brackets:
local string1 = [[Helloworld!Hello "world"!Hello 'world'!]]print(string1)--> Hello--> world!--> Hello "world"!--> Hello 'world'!
If necessary, you can nest multiple brackets inside a string using the same number of equal signs in both the beginning and ending bracket:
local string1 = [=[Hello[[world!]]]=]print(string1)--> Hello--> [[world!]]
Combining Strings
To combine strings, concatenate them with two dots (..). Concatenating strings doesn't insert a space between them, so you'll need to include space(s) at the end/beginning of a preceding/subsequent string, or concatenate a space between the two strings.
local hello = "Hello"local helloWithSpace = "Hello "local world = "world!"local string1 = hello .. worldlocal string2 = helloWithSpace .. worldlocal string3 = hello .. " " .. worldprint(string1) --> Helloworld!print(string2) --> Hello world!print(string3) --> Hello world!
Note that the print() command takes multiple arguments and combines them with spaces, so you can use , instead of .. to yield spaces in print() outputs.
local hello = "Hello"local world = "world"local exclamationMark = "!"print(hello .. world .. exclamationMark) --> Helloworld!print(hello, world .. exclamationMark) --> Hello world!print(hello, world, exclamationMark) --> Hello world !
Converting Strings
To convert a string to a number, use the tonumber() function. If the string doesn't have a number representation, tonumber() returns nil.
local numericString = "123"print(tonumber(numericString)) --> 123local alphanumericString = "Hello123"print(tonumber(alphanumericString)) --> nil
Escaping Strings
To escape a double- or single-quote string declaration and embed almost any character, put a backslash (\) before the character. For example:
- To embed a single quote in a single-quote string, use \'.
- To embed a double quote in a double-quote string, use \".
local string1 = 'Hello \'world\'!'print(string1) --> Hello 'world'!local string2 = "Hello \"world\"!"print(string2) --> Hello "world"!
Certain characters following backslashes produce special characters rather than escaped characters:
- To embed a new line, use \n.
- To embed a horizontal tab, use \t.
local string1 = "Hello\nworld!"print(string1)--> Hello--> world!local string2 = "Hello\tworld!"print(string2) --> Hello world!
String Interpolation
Luau supports string interpolation, a feature that lets you insert expressions into strings. Use backticks (`) to declare an interpolated string, then add expressions inside of curly brackets:
local world = "world"local string1 = `Hello {world}!`print(string1) --> Hello world!
Although variables are the most common usage, you can use any expression, including math:
local world = "world"local number = 1local letters = {"w", "o", "r", "l", "d"}local string1 = `Hello {world}, {number} time!`local string2 = `Hello {world}, {number + 1} times!`local string3 = `Hello {table.concat(letters)} a third time!`print(string1) --> Hello world, 1 time!print(string2) --> Hello world, 2 times!print(string3) --> Hello world a third time!
Standard escape rules apply for backticks, curly brackets, and backslashes:
local string1 = `Hello \`\{world\}\`!`print(string1) --> Hello `{world}`!
Math Conversion
If you perform math operations on a string, Luau automatically converts the string to a number. If the string doesn't have a number representation, it throws an error.
print("55" + 10) --> 65print("55" - 10) --> 45print("55" * 10) --> 550print("55" / 10) --> 5.5print("55" % 10) --> 5print("Hello" + 10) --> print("Hello" + 10):1: attempt to perform arithmetic (add) on string and number
Comparisons
Strings can be compared using the <, <=, > and >= operators which compare using lexicographical order based on the ASCII codes of each character in a string. This will result in numbers in strings not being compared correctly, for example, "100" will be less than "20", since the bytes "0" and "1" have lower ASCII codes than byte "2".
print("Apple" < "apple") --> trueprint("Banana" < "apple") --> true (B is before a in ASCII)print("number100" < "number20") --> true
String Pattern Reference
A string pattern is a combination of characters that you can use with string.match(), string.gmatch(), and other functions to find a piece, or substring, of a longer string.
Direct Matches
You can use direct matches in a Luau function like string.match(), except for magic characters. For example, these commands look for the word Roblox within a string:
local match1 = string.match("Welcome to Roblox!", "Roblox")local match2 = string.match("Welcome to my awesome game!", "Roblox")print(match1) --> Robloxprint(match2) --> nil
Character Classes
Character classes are essential for more advanced string searches. You can use them to search for something that isn't necessarily character-specific but fits within a known category (class), including letters, digits, spaces, punctuation, and more.
The following table shows the official character classes for Luau string patterns:
Class | Represents | Example Match |
---|---|---|
. | Any character | 32kasGJ1%fTlk?@94 |
%a | An uppercase or lowercase letter | aBcDeFgHiJkLmNoPqRsTuVwXyZ |
%l | A lowercase letter | abcdefghijklmnopqrstuvwxyz |
%u | An uppercase letter | ABCDEFGHIJKLMNOPQRSTUVWXYZ |
%d | Any digit (number) | 0123456789 |
%p | Any punctuation character | !@#;,. |
%w | An alphanumeric character (either a letter or a number) | aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789 |
%s | A space or whitespace character | , \n, and \r |
%c | A special control character | |
%x | A hexadecimal character | 0123456789ABCDEF |
%z | The NULL character (\0) |
For single-letter character classes such as %a and %s, the corresponding uppercase letter represents the "opposite" of the class. For instance, %p represents a punctuation character while %P represents all characters except punctuation.
Magic Characters
There are 12 "magic characters" which are reserved for special purposes in patterns:
$ | % | ^ | * | ( | ) |
. | [ | ] | + | - | ? |
You can escape and search for magic characters using the % symbol. For example, to search for roblox.com, escape the . (period) symbol by preceding it with a % as in %..
-- "roblox.com" matches "roblox#com" because the period is interpreted as "any character"local match1 = string.match("What is roblox#com?", "roblox.com")print(match1) --> roblox#com-- Escape the period with % so it is interpreted as a literal period characterlocal match2 = string.match("I love roblox.com!", "roblox%.com")print(match2) --> roblox.com
Anchors
You can search for a pattern at the beginning or end of a string by using the ^ and $ symbols.
local start1 = string.match("first second third", "^first") -- Matches because "first" is at the beginningprint(start1) --> firstlocal start2 = string.match("third second first", "^first") -- Doesn't match because "first" isn't at the beginningprint(start2) --> nillocal end1 = string.match("first second third", "third$") -- Matches because "third" is at the endprint(end1) --> thirdlocal end2 = string.match("third second first", "third$") -- Doesn't match because "third" isn't at the endprint(end2) --> nil
You can also use both ^ and $ together to ensure a pattern matches only the full string and not just some portion of it.
-- Using both ^ and $ to match across a full stringlocal match1 = string.match("Roblox", "^Roblox$") -- Matches because "Roblox" is the entire string (equality)print(match1) --> Robloxlocal match2 = string.match("I play Roblox", "^Roblox$") -- Doesn't match because "Roblox" isn't at the beginning AND endprint(match2) --> nillocal match3 = string.match("I play Roblox", "Roblox") -- Matches because "Roblox" is contained within "I play Roblox"print(match3) --> Roblox
Class Modifiers
By itself, a character class only matches one character in a string. For instance, the following pattern ("%d") starts reading the string from left to right, finds the first digit (2), and stops.
local match = string.match("The Cloud Kingdom has 25 power gems", "%d")print(match) --> 2
You can use modifiers with any character class to control the result:
Quantifier | Meaning |
---|---|
+ | Match 1 or more of the preceding character class |
- | Match as few of the preceding character class as possible |
* | Match 0 or more of the preceding character class |
? | Match 1 or less of the preceding character class |
%n | For n between 1 and 9, matches a substring equal to the nth captured string. |
%bxy | The balanced capture matching x, y, and everything between (for example, %b() matches a pair of parentheses and everything between them) |
Adding a modifier to the same pattern ("%d+" instead of "%d"), outputs 25 instead of 2:
local match1 = string.match("The Cloud Kingdom has 25 power gems", "%d")print(match1) --> 2local match2 = string.match("The Cloud Kingdom has 25 power gems", "%d+")print(match2) --> 25
Class Sets
Sets should be used when a single character class can't do the whole job. For instance, you might want to match both lowercase letters (%l) and punctuation characters (%p) using a single pattern.
Sets are defined by brackets [] around them. In the following example, notice the difference between using a set ("[%l%p]+") and not using a set ("%l%p+").
local match1 = string.match("Hello!!! I am another string.", "[%l%p]+") -- Setprint(match1) --> ello!!!local match2 = string.match("Hello!!! I am another string.", "%l%p+") -- Non-setprint(match2) --> o!!!
The first command (set) tells Luau to find both lowercase characters and punctuation. With the + quantifier added after the entire set, it finds all of those characters (ello!!!), stopping when it reaches the space.
In the second command (non-set), the + quantifier only applies to the %p class before it, so Luau grabs only the first lowercase character (o) before the series of punctuation (!!!).
Like character classes, sets can be "opposites" of themselves. This is done by adding a ^ character at the beginning of the set, directly after the opening [. For instance, "[%p%s]+" represents both punctuation and spaces, while "[^%p%s]+" represents all characters except punctuation and spaces.
Sets also support ranges which let you find an entire range of matches between a starting and ending character. This is an advanced feature which is outlined in more detail on the Lua 5.1 Manual.
String Captures
String captures are sub-patterns within a pattern. These are enclosed in parentheses () and are used to get (capture) matching substrings and save them to variables. For example, the following pattern contains two captures, (%a+) and (%d+), which return two substrings upon a successful match.
local pattern = "(%a+)%s?=%s?(%d+)"local key1, val1 = string.match("TwentyOne = 21", pattern)print(key1, val1) --> TwentyOne 21local key2, val2 = string.match("TwoThousand= 2000", pattern)print(key2, val2) --> TwoThousand 2000local key3, val3 = string.match("OneMillion=1000000", pattern)print(key3, val3) --> OneMillion 1000000
In the previous pattern, the ? quantifier that follows both of the %s classes is a safe addition because it makes the space on either side of the = sign optional. That means the match succeeds if one (or both) spaces are missing around the equal sign.
String captures can also be nested as the following example:
local places = "The Cloud Kingdom is heavenly, The Forest Kingdom is peaceful"local pattern = "(The%s(%a+%sKingdom)[%w%s]+)"for description, kingdom in string.gmatch(places, pattern) doprint(description)print(kingdom)end--> The Cloud Kingdom is heavenly--> Cloud Kingdom--> The Forest Kingdom is peaceful--> Forest Kingdom
This pattern search works as follows:
The string.gmatch() iterator looks for a match on the entire "description" pattern defined by the outer pair of parentheses. This stops at the first comma and captures the following:
# | Pattern | Capture |
---|---|---|
1 | (The%s(%a+%sKingdom)[%w%s]+) | The Cloud Kingdom is heavenly |
Using its successful first capture, the iterator then looks for a match on the "kingdom" pattern defined by the inner pair of parentheses. This nested pattern simply captures the following:
# | Pattern | Capture |
---|---|---|
2 | (%a+%sKingdom) | Cloud Kingdom |
The iterator then backs out and continues searching the full string, capturing the following:
# | Pattern | Capture |
---|---|---|
3 | (The%s(%a+%sKingdom)[%w%s]+) | The Forest Kingdom is peaceful |
4 | (%a+%sKingdom) | Forest Kingdom |
In addition to all of the above, there is a special case with an empty capture (()). If a capture is empty, then the position in the string will be captured:
local match1 = "Where does the capture happen? Who knows!"local match2 = "This string is longer than the first one. Where does the capture happen? Who knows?!"local pattern = "()Where does the capture happen%? Who knows!()"local start1, finish1 = string.match(match1, pattern)print(start1, finish1) --> 1 42local start2, finish2 = string.match(match2, pattern)print(start2, finish2) --> 43 84
These special captures may be nested like normal ones:
local places = "The Cloud Kingdom is heavenly, The Forest Kingdom is peaceful."local pattern = "The (%a+()) Kingdom is %a+"for kingdom, position in string.gmatch(places, pattern) doprint(kingdom, position)end--> Cloud 10--> Forest 42
The returned values are unusual in that they are numbers rather than strings:
local match = "This is an example"local pattern = "This is an ()example"local position = string.match(match, pattern)print(typeof(position)) --> number