--- title: Strings description: A sequence of characters, such as letters, numbers, and symbols. --- 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. ## Declare 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, enclose your string in the other type of quote, or use an [escaped quote](#escape-strings). ```lua 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: ```lua local string1 = [[Hello world! 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: ```lua local string1 = [=[Hello [[world!]] ]=] print(string1) --> Hello --> [[world!]] ``` ## Combine 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. ```lua local hello = "Hello" local helloWithSpace = "Hello " local world = "world!" local string1 = hello .. world local string2 = helloWithSpace .. world local string3 = hello .. " " .. world print(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. ```lua 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 ! ``` ## Convert strings To convert a string to a number, use the `Global.LuaGlobals.tonumber()` function. If the string doesn't have a number representation, `Global.LuaGlobals.tonumber()` returns `nil`. ```lua local numericString = "123" print(tonumber(numericString)) --> 123 local alphanumericString = "Hello123" print(tonumber(alphanumericString)) --> nil ``` ## Escape 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 `\"`. ```lua 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`. ```lua 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: ```lua 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: ```lua local world = "world" local number = 1 local 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: ```lua 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. ```lua print("55" + 10) --> 65 print("55" - 10) --> 45 print("55" * 10) --> 550 print("55" / 10) --> 5.5 print("55" % 10) --> 5 print("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"`. ```lua print("Apple" < "apple") --> true print("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 `Library.string.match()`, `Library.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 `Library.string.match()`, except for [magic characters](#magic-characters). For example, these commands look for the word **Roblox** within a string: ```lua local match1 = string.match("Welcome to Roblox!", "Roblox") local match2 = string.match("Welcome to my awesome game!", "Roblox") print(match1) --> Roblox print(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 `%.`. ```lua -- "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 character local 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. ```lua local start1 = string.match("first second third", "^first") -- Matches because "first" is at the beginning print(start1) --> first local start2 = string.match("third second first", "^first") -- Doesn't match because "first" isn't at the beginning print(start2) --> nil local end1 = string.match("first second third", "third$") -- Matches because "third" is at the end print(end1) --> third local end2 = string.match("third second first", "third$") -- Doesn't match because "third" isn't at the end print(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. ```lua -- Using both ^ and $ to match across a full string local match1 = string.match("Roblox", "^Roblox$") -- Matches because "Roblox" is the entire string (equality) print(match1) --> Roblox local match2 = string.match("I play Roblox", "^Roblox$") -- Doesn't match because "Roblox" isn't at the beginning AND end print(match2) --> nil local 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. ```lua 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`: ```lua local match1 = string.match("The Cloud Kingdom has 25 power gems", "%d") print(match1) --> 2 local 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+"`). ```lua local match1 = string.match("Hello!!! I am another string.", "[%l%p]+") -- Set print(match1) --> ello!!! local match2 = string.match("Hello!!! I am another string.", "%l%p+") -- Non-set print(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](https://www.lua.org/manual/5.1/manual.html#5.4.1). ### 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. ```lua local pattern = "(%a+)%s?=%s?(%d+)" local key1, val1 = string.match("TwentyOne = 21", pattern) print(key1, val1) --> TwentyOne 21 local key2, val2 = string.match("TwoThousand= 2000", pattern) print(key2, val2) --> TwoThousand 2000 local key3, val3 = string.match("OneMillion=1000000", pattern) print(key3, val3) --> OneMillion 1000000 ``` 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. In the `Library.string.gsub()` function, you can include capture groups in the replacement string using `%1`, `%2`, `%3`, etc., up to `%9`. Even though Luau supports up to 32 capture groups before throwing an error, you can only reference the first nine with this syntax: ```lua local str = "love2play Roblox" local pattern = "(%w+)(%d+)(%w+)%s+(%w+)" local replacement = "I %1 %2 %3 %4!" local result = string.gsub(str, pattern, replacement) print(result) --> I love 2 play Roblox! ``` You can also nest string captures: ```lua 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) do print(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 `Library.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: ```lua 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 42 local start2, finish2 = string.match(match2, pattern) print(start2, finish2) --> 43 84 ``` These special captures may be nested like normal ones: ```lua 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) do print(kingdom, position) end --> Cloud 10 --> Forest 42 ``` The returned values are unusual in that they are **numbers** rather than strings: ```lua local match = "This is an example" local pattern = "This is an ()example" local position = string.match(match, pattern) print(typeof(position)) --> number ```