What are String Patterns?
String patterns, is a specific arrangement or sequence of characters within a text or a string. For example, if you’re looking for all the numbers in a set of strings, you can create a string pattern that captures only the numbers in each string, (e.g “helloworld123”, pattern: “%d+”).
The Usage of String Patterns
- Search and Identify: You can create patterns to search for specific text within strings. For instance, you could use a string pattern to find all player names that start with “Ro”, allowing you to target or modify those players in your game.
- Filter and Validate: String patterns help you filter input or validate user data. For example, you might ensure that an input-based setting follows a specific pattern before allowing them to change the setting
- Formatting and Parsing: String patterns are useful for formatting text in a specific way or parsing data from strings. You could split a string into parts using a specific pattern, like breaking down a date string into day, month, and year.
The Basics
There are currently 3 string pattern methods you can utilize:
-
string.match
Looks for the first match in the string, returns the match -
string.gmatch
Looks for all matches in the string, returns an iterator function -
string.gsub
Looks for all matches in the string and replaces them accordingly, returns the replaced string
Class | Represents |
---|---|
. |
Any character |
%a |
An uppercase or lowercase letter |
%l |
A lowercase letter |
%u |
An uppercase letter |
%d |
Any digit (number) |
%p |
Any punctuation character |
%w |
An alphanumeric character (either a letter or a number) |
%s |
A space or whitespace character |
%c |
A special control character |
%x |
A hexadecimal character |
%z |
The NULL character (\0 ) |
Source: Strings | Documentation - Roblox Creator Hub
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.
Character | Usage |
---|---|
$ |
Search exclusively at the end of the string (e.g roblox$ ) |
^ |
Search exclusively at the beginning of the string (e.g ^ilove ) |
( and )
|
Groups part of the pattern together, returns the capture separately (e.g (%d+)(%a) ) |
[ and ]
|
Defines a set of characters from which you want to match a class (e.g [%w%p] ) |
+ |
A quantifier of one or more class |
- |
A quantifier to match as few of the class possible, could also be used to define a range of characters (e.g [A-Z] ) |
? |
A quantifier of 1 or less class |
* |
A quantifier of 0 or more class |
Applying the characters above to the same pattern:
-
%d+
, matches with01
,53
,159
,009
,1000
-
%d$
, matches withabc1
,helloworld9
,10
,0
,was that a bite of 87
-
^%d+
, matches with190k
,10m
,10kg
,87
-
(%d+)(%a+)
, matches with100k
,100m
,100L
,100kg
-
[%d%p]+
, matches with100,000
,69,420
,500.00
-
%d?
, matches with1
,10
,59
,1000
,008
-
%d*
, matches withabcdefg
,hello1world
,h3llo world
,109
%l
= lowercase letters%d
= digits%p
= punctuations.
= any characters
String patterns may be unpredictable, and that’s fine! I had a lot of troubles memorizing and testing how would a pattern work out, and for that, i made a plugin that helps you test string patterns right from your studio environment
Plugin: https://web.roblox.com/library/13941603210/RegExplorer
Devforum Post: RegExplorer - a free tool to test string patterns
Scenarios
Here, i made a couple of scenarios to test your string pattern (and maybe problem solving) skills. If you found other solutions, let me know!
-
Custom Commands
You want to create a command handler that handles and parses the message into a data it can use. An admin can use commands such as/teleport Artzified
,/kill Artzified
. What pattern and methods should you use to achieve this?
Solution
local command, args = string.match(message, "/(%w+) (.+)") -- gets the command (%w+) and args string (.+)
local argsTable = {}
for argument in args:gmatch("%S") do -- gets all the arguments
table.insert(argsTable, argument) -- inserts the arguments to the table
end
handleCommand(command, argsTable) -- handle the command
-
NPC Dialogues
Developing an NPC (non-playable character) system where dialogue responses are formatted based on the player name
local responses = {
"Greetings, {user}!",
"Hello there, {user}",
"Hi {user}, anything you'd like to discuss?"
}
How would you get a random response and format it accordingly?
Solution
local response = responses[math.random(#responses)] -- get a random response
response = response:gsub("{user}", player.Name) -- replace "{user}" with the player's name
-
The Password Game
You might’ve heard of the Password Game, which you need to apply each rule to your password, now we’re gonna sort of recreate it on a smaller scale. How do you make it so that the user has to have all numbers in their password to add up to 25?
Solution
local sum = 0 -- define the initial sum
for num in string.gmatch(password, "%d") do -- iterate over all digits in the password
sum += num -- increase the sum by the single-digit number
end
local isValid = sum == 25 -- does sum add up to 25?
return isValid
-
Form Validation
You’re building a registration page for your, say very professional moderator. Users are required to put their email address for the form response. How do you make validate the email the user has inputted?
Solution
local match = string.match(email_address, "(%w+)@(%a+)%.com") -- (name)@(domain).com
return match ~= nil -- is it valid?
-
Data Extraction
You’re working on a data extraction project. You have a table containing URLs, and you need to extract all the domain names from the URLs.
local urls = {
"roblox.com",
"https://google.com",
"www.wikipedia.com"
}
How do you achieve this?
Solution
local domains = {} -- store the domains
for url in urls do
local domain = url:match("w?%.?(%w+)%..+") -- www(optional).(domain).(any)
table.insert(domains, domain)
end
return domains
-
Setting Input Validation
You have a setting input where users can configure the setting to their preferences, but you haven’t implemented a check validation if the setting is a number, or a bunch of letters? How do you check if the user input is a number?
Solution
There are 2 working solutions in this scenario, one with a simple %d+
, and the other utilizing the set - range pattern
local isNumber = string.match(input, "%d+") ~= nil
return isNumber
local isNumber = string.match(input, "[0-9]+") ~= nil
return isNumber
-
Text Highlighting
You want to make a text-highlighting system to highlight certain words within a string. For instance, the string is “When life gives you lemons”, and the highlight word is “lemon”, then the word “lemon” will be wrapped with<highlight>
and ends with</highlight>
(When life gives you <highlight>lemon</highlight>s
). How do you do this?
Solution
local highlightedWord = "lemon"
local modifiedString = sample:gsub(highlightedWord, function()
return `<highlight>{highlightedWord}</highlight>` -- returns the replacement text
end)
-
A (simple) statement interpreter
You have a state machine, in which you have a list of string statements that you have to evaluate.
For example, you have the string: “advantage: 0; dist: >20”, which should translate to:
advantage == 0 and dist > 20
or you have the string: “!attack; dist: >12; advantage: >1”, which translates into:
not attack and dist > 12 and advantage > 1
and say, you also want to make a range function: “disadvantage: range(2, 4); dist:>7.5”, which should translate into:
disadvantage >= 2 and disadvantage <= 4 and dist > 7.5
and also it should support the <
operator: “disadvantage: range(2, 4); dist:<7”
This is your code template to begin with:
local variables = {
disadvantage = -advantage;
advantage = advantage;
attack = attacking;
dist = dist;
}
local predicateString
local statements = predicateString:split(';')
local evaluation = {}
for _, statement in statements do
end
for _, eval in evaluation do -- all statements are using AND
if eval == false then
return false
end
end
return true
Evaluation is a table of the statements evaluated, for instance; the predicate: “disadvantage: >5; dist:<7”; with disadvantage set to 6 and dist set to 8, should have an evaluation table of {true, false}
Solution
local variables = {
disadvantage = -advantage;
advantage = advantage;
attack = attacking;
dist = dist;
}
local predicateString
local statements = predicateString:split(';')
local evaluation = {}
for _, statement in statements do
local negation, variable, operator, treshold = statement:match('(!?)(%l+):?([><]?)([%d%p]*)')
local min_range, max_range = statement:match('range%([%d%.]+,[%d%.]+%)')
local variable_value = variables[variable]
assert(variable_value ~= nil, `Variable {variable} does not exists`)
local statement_evaluation = false
treshold = tonumber(treshold)
if treshold then
if operator == '>' then
statement_evaluation = variable_value > treshold
elseif operator == '<' then
statement_evaluation = variable_value < treshold
elseif operator == '' and treshold ~= '' then
statement_evaluation = variable_value == treshold
end
end
if min_range and max_range then
min_range = tonumber(min_range)
max_range = tonumber(max_range)
statement_evaluation = variable_value >= min_range and variable_value <= max_range
end
if negation ~= '' then
statement_evaluation = not statement_evaluation
end
table.insert(evaluation, statement_evaluation)
end
for _, eval in evaluation do
if eval == false then -- all statements are using AND
return false
end
end
return true