mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-24 06:34:09 +00:00
602 lines
17 KiB
Markdown
602 lines
17 KiB
Markdown
---
|
|
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:
|
|
|
|
<table>
|
|
<thead>
|
|
<th>Class</th>
|
|
<th>Represents</th>
|
|
<th>Example Match</th>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>.</code></td>
|
|
<td>Any character</td>
|
|
<td><code>32kasGJ1%fTlk?@94</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%a</code></td>
|
|
<td>An uppercase or lowercase letter</td>
|
|
<td><code>aBcDeFgHiJkLmNoPqRsTuVwXyZ</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%l</code></td>
|
|
<td>A lowercase letter</td>
|
|
<td><code>abcdefghijklmnopqrstuvwxyz</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%u</code></td>
|
|
<td>An uppercase letter</td>
|
|
<td><code>ABCDEFGHIJKLMNOPQRSTUVWXYZ</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%d</code></td>
|
|
<td>Any digit (number)</td>
|
|
<td><code>0123456789</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%p</code></td>
|
|
<td>Any punctuation character</td>
|
|
<td><code>!@#;,.</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%w</code></td>
|
|
<td>An alphanumeric character (either a letter <b>or</b> a number)</td>
|
|
<td><code>aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%s</code></td>
|
|
<td>A space or whitespace character</td>
|
|
<td><code> </code>, <code>\n</code>, and <code>\r</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%c</code></td>
|
|
<td>A special <a href="https://wikipedia.org/wiki/Control_character">control character</a></td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%x</code></td>
|
|
<td>A hexadecimal character</td>
|
|
<td><code>0123456789ABCDEF</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%z</code></td>
|
|
<td>The NULL character (<code>\0</code>)</td>
|
|
<td></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
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:
|
|
|
|
<table>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>$</code></td>
|
|
<td><code>%</code></td>
|
|
<td><code>^</code></td>
|
|
<td><code>*</code></td>
|
|
<td><code>(</code></td>
|
|
<td><code>)</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>.</code></td>
|
|
<td><code>[</code></td>
|
|
<td><code>]</code></td>
|
|
<td><code>+</code></td>
|
|
<td><code>-</code></td>
|
|
<td><code>?</code></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
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:
|
|
|
|
<table>
|
|
<thead>
|
|
<th>Quantifier</th>
|
|
<th>Meaning</th>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>+</code></td>
|
|
<td>Match 1 or more of the preceding character class</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>-</code></td>
|
|
<td>Match as few of the preceding character class as possible</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>*</code></td>
|
|
<td>Match 0 or more of the preceding character class</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>?</code></td>
|
|
<td>Match 1 or less of the preceding character class</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%n</code></td>
|
|
<td>For <code>n</code> between <b>1</b> and <b>9</b>, matches a substring equal to the <code>n</code>th captured string.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>%bxy</code></td>
|
|
<td>The balanced capture matching <code>x</code>, <code>y</code>, and everything between (for example, <code>%b()</code> matches a pair of parentheses and everything between them)</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
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:
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th width="8%">#</th>
|
|
<th width="42%">Pattern</th>
|
|
<th>Capture</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><b>1</b></td>
|
|
<td><code>(The%s(%a+%sKingdom)[%w%s]+)</code></td>
|
|
<td>The Cloud Kingdom is heavenly</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
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:
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th width="8%">#</th>
|
|
<th width="42%">Pattern</th>
|
|
<th>Capture</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><b>2</b></td>
|
|
<td><code>(%a+%sKingdom)</code></td>
|
|
<td>Cloud Kingdom</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
The iterator then backs out and continues searching the full string, capturing
|
|
the following:
|
|
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th width="8%">#</th>
|
|
<th width="42%">Pattern</th>
|
|
<th>Capture</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><b>3</b></td>
|
|
<td><code>(The%s(%a+%sKingdom)[%w%s]+)</code></td>
|
|
<td>The Forest Kingdom is peaceful</td>
|
|
</tr>
|
|
<tr>
|
|
<td><b>4</b></td>
|
|
<td><code>(%a+%sKingdom)</code></td>
|
|
<td>Forest Kingdom</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
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
|
|
```
|