Understanding The string Library

Like many documentations on the DevHub, the string library function descriptions aren’t very useful and can be a little convoluted for even the most seasoned developer. Because of my initial confusion with the string library, I’ll be doing my best to explain each function in layman’s terms.

string.byte()

Return type: Tuple (int)
Parameters: str (string), startIndex (int), endIndex (int)

This function returns the internal numerical codes of the given characters of str from startIndex to endIndex.

If startIndex isn’t specified, then it defaults to 1. If an endIndex isn’t specified, it defaults to startIndex.

The byte codes seem to correspond with the ASCII table decimal values. Here is an ASCII table.

string.char()

Return type: string
Parameters: int (Can be a tuple of int values)

This function pretty much does the opposite of string.byte(). It takes a dec value from the ASCII table and returns the corresponding character.

Code Sample For string.byte() & string.char()
local byte = string.byte("T"); --> 84
local char = string.char(byte); --> "T"

local helloBytes = table.pack(string.byte("Hello world!", 1, 5)); --> {72, 101, 108, 108, 111}

--Remember, string.byte returns a tuple. 
--If the startIndex and endIndex aren't the same, it'll return multiple values.
--Using table.pack() on a tuple turns the tuple into a table, 
--which is more convenient than assigning multiple variables for each tuple value.

local helloChar = string.char(table.unpack(helloBytes)); --> "Hello"

--Table.unpack() turns a table into a tuple, and since string.char() accepts tuples, 
--we can turn it into a string!

string.find()

Return Type: Tuple (int)
Parameters: stringToSearch (string), patternToFind (string), startIndex (int), ignorePatterns (boolean)

By default, startIndex is 1, and ignorePatterns is false.

This function finds the start and end index of patternToFind in stringToSearch. If not found, it returns nil.

If ignorePatterns is true, string.find() looks at raw text, and ignores string pattern formatting. See string patterns here.
Also, remember that you must specify a startIndex if you do use ignorePatterns.

Code Samples for string.find()
local helloWorld = "Hello world!";
local world = string.find(helloWorld, "world"); --> 7, 11

local firstLetterL = string.find(helloWorld, "l"); --> 3, 3
local secondLetterL = string.find(helloWorld, "l", 4); --> 4, 4

local message = "Hello, we are contacting you about your car's extended warranty.";

local findUppercaseLetter = string.find(message, "%u"); --> 1, 1
--%u is the string pattern for "uppercase character"

local plainFindUppercaseLetter = string.find(message, "%u", 1, true); --> nil
--Remember that if ignorePatterns is true, it tries to find "%u", not an uppercase character.

string.format()

Return type: string
Parameters: stringToFormat (string), stringsToAdd (Tuple)

For this function to work, the stringToFormat argument must contain a segment which follows the following format: %[flag] [width] [.precision] [specifier]

If you don’t use a certain element of the format, there are defaults that are used instead. The only parameter you must have is the specifier. Otherwise, you will get an error. Other than that, every other parameter is completely optional.

Understanding flags, width, precision, & specifiers

Flags

The - flag puts width characters on the right of the string.

The + flag puts width characters on the left side of the string. (If no flag is specified, this is the default)

The # flag only works with the e, f, g, o, or x specifiers.

  • For e, f, and g it forces a decimal point with zeroes.
  • For o and x, it puts a zero before all non-zero values.

The 0 flag acts like the - flag but uses 0s instead of spaces when padding out.

Code Examples For Flags
local leftFormat = "%-30s"; --This is a format with the - flag, 30 width, and string specifier.
local leftString = string.format(leftFormat, "Format this to the left!"); --> "      Format this to the left!"
--Since the given string had 24 characters, it will tack on 6 spaces to fulfill the 30 width requirement specified
print(leftString)

local rightFormat = "%+30s"; --This format will pad out the 'right' side of the string, ensuring 3O characters.
local rightString = string.format(rightFormat, "Format this to the right!"); --> "Format this to the right!     "
--Since the given string had 25 characters, it will tack on 5 spaces to fulfill the 30 width requirement.

local eFormat = "%#e" --The 'e' specifier converts the given number into scientific notation. An example would be 3e3, which is 3 x 10 x 10 x 10.
--In scientific notation, the number which follows e is how many times to raise the first number by 10
--The way roblox displays e numbers with string.format is with like this: 5e2 == 5e+03
--Examples: 5e3 == 5000, 1.5e1 == 15, 7.32e4 == 73200, 6.2123e3 == 6212.3
local eString = string.format(eFormat, "5421"); --> "5.421000e+03"
--Fun-ish fact, capitalizing the E in the format string will make the output have a capital E as well.
--I'm not sure if this is intentional, but the results I got with and without the # flag were the same, even with non-float numbers.

local fFormat = "%#f" --This is a format with the # flag, and a float specifier.
--This format will ensure a decimal placement, even if a number does not go in the decimal place.
local fString = string.format(fFormat, "5"); --> "5.000000" (without the '#' flag, the output would be "5")

local gFormat = "%#g"; --The 'g' format is similar to the 'e' specifier, but shorter.
local gString = string.format(gFormat, "50"); --> "50.0000" (without the '#' flag, the output would be "50")

local oFormat = "%#o"; --> The 'o' specifier turns a given number into base 8. With the '#' flag, a 0 is always put in front of the output.
local oString = string.format(oFormat, "8"); --> "010" (without the '#' flag, the output would be 10)

local xFormat = "%#x"; -->The 'x' specifier turns a given number into base 16. The '#' flag here behaves the same as the 'o' specifier, but also adds an "x" or "X" (depending on the capitalization)
--The x goes after the 0.
local xString = string.format(xFormat, "19"); --> "0x13" (without the '#' flag, the output would be "13")

local zeroFormat = "%025s"; --The zero format with a minimum of 25 characters. Remember that this behaves like the '-' flag, but pads using zeroes instead of spaces.
local zeroString = string.format(zeroFormat, "Pad this with zeroes"); --> "00000Pad this with zeroes"

Width

The width is the minimum amount of characters a formatted string must have. If the requirement is not met, it pads the string out with spaces, or 0s if using the 0 flag. The side on which the padding goes on is determined by if you use the + or - flag.

The default value for width is 0, and the maximum value is 99.

Precision

For integer-based specifiers, the value used for Precision is the minimum amount of digits to be used. If the presumed length is less than the specified length, the rest is padded out with leading zeroes.

For the e and f specifiers, this is the minimum amount of digits to be affixed in the decimal place.
For the g specifier, this is the maximum number of digits that can be present before the E value.
For the s specifier, this is the minimum amount of characters to be returned.

Code Samples For Precision
--To declare the precision parameter, you type ".x", with x being the precision you desire.

local floatFormat = "That will be $%.2f"; --> A float number which must have at least 2 decimal places.
local floatString = string.format(floatFormat, "5"); --> "That will be $5.00"

local eFormat = "%.5e"; -- A scientific notation number which must have at least 1 decimal place.
local eString = string.format(eFormat, "232100"); --> "2.0e+00" (as you can see, this does not apply to the e value.)
--From what I observed, the precision parameter overrides the '#' flag's forced decimal places.

local gFormat = "%.3g"; -- A short scientific notation number which can have at most 3 numbers before the e+ value.
local gString = string.format(gFormat, "51531"); --> "5.15e+04"
--If the number was instead "51031", the output would be "5.1e+04"

local sFormat = "My name is %.7s"; --A string which can have at most 7 characters.
local sFormat = string.format(sFormat, "jelliedbanana"); --> "My name is jellied"

Specifiers

I’ve mentioned quite a few of these already, but there are some I haven’t mentioned yet.

The c specifier is an integer.
The d specifier is a base-10 number.
The q specifier wraps the given string in double quotes.

string.gmatch()

Return type: function
Parameters: stringToSearch (string), stringPattern (string)

The function returned will return each new occurrence of the given stringPattern until there are no more occurrences. When this happens, it will return nil instead.

Code Sample For string.gmatch()
local iteratorFunc = string.gmatch("Hello world!", "l");

for i = 1, 4 do
	iteratorFunc(); --> "l", "l", "l", nil
end

string.gsub()

Return type: string, int
Parameters: str (string), stringPattern (string), patternReplacement (string/table/function), maxReplacements (int)

If maxReplacements is not specified, there will not be a maximum.

This function replaces each occurrence of stringPattern in str with patternReplacement until there are either no more occurences, or the maxReplacements is exceeded.

patternReplacement can be either a string, table, or lua function.

In the case of a table, it must be a dictionary where the occurences are the keys, and the values are what you want to replace them with. This is useful primarily when using one of the various string patterns in the stringPattern parameter.

As for a function, string.gsub() passes the occurence to the function, and that function must return a value which will replace the occurence.

Code Samples For string.gsub()
local gsubA = string.gsub("I love tomatoes.", "love", "hate"); --> "I hate tomatoes.", 1

local gsubB = string.gsub("plr1 just owned plr2 and plr3", "%w+", {plr1 = "Shedletsy", plr2 = "Builderman", plr3 = "Telamon"}); --> "Shedletsky just owned Builderman and Telemon", 3
--The %w string pattern looks for whole words. The '+' special character ensures the pattern will match 1 or more digit.
--If you use a table as the replacement, stringPatterns which aren't present in the table will be unaffected, hence why only 'plr1', 'plr2', and 'plr3' were swapped out.

local gsubC = string.gsub("Let's play 5 roblox games!", "%d+", function(num)
	return num + 5;
end) --> "Let's play 10 roblox games!", 1
--The %d string pattern looks for numbers. Anything which matches the stringPattern will be passed to the function.

string.len()

Return type: int
Parameters: str (string)

This function returns the length of a string.

Code Sample For string.len()
local length = string.len("According to all known laws of aviation, there is no way that a bee should be able to fly."); --> 90

string.lower()

Return type: string
Parameters: stringToLower (string)

Returns stringToLower, except every character is lowercase.

Code Sample For string.lower()
local length = string.lower("HELP MY CAPS LOCK KEY IS STUCK"); --> "help my caps lock key is stuck"

string.match()

Return type: string
Parameters: stringToSearch (string), patternToMatch (string), startIndex (int)

This function looks for the first occurence of patternToMatch at index startIndex, and returns it. If no match is found, nil is returned instead. Unlike string.find(), the index at which the pattern is found is not returned.

Code Samples For string.match()
local match = string.match("I have 4 dollars in my wallet.", "%d+"); --> "4"
--The %d+ pattern looks for numbers.

local match2 = string.match("I have 2 quarters and 890 nickels.", "%d+", 10); --> "890"
--Since the given index is after the index of "2", it looks for any numbers at or after that index, which is "890".

string.rep()

Return type: string
Parameters: str (string), n (int)

This function takes str, multiples it n times, and returns a string that combines each iteration.

Code Sample For string.rep()
local combinedStr = string.rep("Hi", 5); --> "HiHiHiHiHi"

string.reverse()

Return type: string
Parameters: stringToReverse (string)

This function reverses a given string.

Code Sample for string.reverse()
local backwardsStr = string.reverse("xolboR"); --> "Roblox";

string.split()

Return type: table (string)
Parameters: stringToSplit (string), stringToSeparateBy (string)

If stringToSeparateBy is not specified, it defaults to a comma (",")

This function returns a table of stringToSplit in which each entry are a sequence of characters separated by stringToSeparateBy.

Code Samples For string.split()
local spaceSplit = string.split("Split this sentence by spaces", " "); --> {"Split", "this", "sentence", "by", "spaces"};
local emptySplit = string.split("Double  spaced", " "); --> {"Double", "", "spaced"}; --If there are two separators next to each other, there will be an empty string between them.

string.sub()

Return type: string
Parameters: stringToSub (string), startIndex (int), endIndex, (int)

This function returns all characters of stringToSub from startIndex to endIndex

Code Samples For string.sub()
local subString = string.sub("Hotdogs are not as good as burgers.", 1, 7); --> "Hotdogs"

local subString2 = string.sub("Hotdogs are not as good as burgers.", 1, -9); --> "Hotdogs are not as good as "
--If the startIndex is positive and the endIndex is negative, it will go backwards from startIndex, removing those characters.

local subString3 = string.sub("I am in severe debt.", -6, 20); --"debt."
--Sidenote, index -2 of a string is the last character in that string. So in the above case, index -2 would be "." Index -3 would be "t"

local subString4 = string.sub("I am in severe debt.", 9, 14); --> "severe"

string.upper()

Return type: string
Parameters: stringToUpper (string)

Returns stringToUpper, except every character will be uppercase.

Code Sample For string.upper()
local uppercase = string.upper("hello everyone i have an announcement to make about shadow the hedgehog"); --> "HELLO EVERYONE I HAVE AN ANNOUNCEMENT TO MAKE ABOUT SHADOW THE HEDGEHOG"

fin

That concludes every current function of the string library as of the time of this writing. It was interesting learning what string patterns were, as I hadn’t ever worked with them before, but I’ll probably end up using them in the near future.

If there was something I could’ve explained better or just got completely wrong, please let me know! My aim is to make this guide as coherent as possible, and I personally think I did a good job at it. I hope this helped you to understand strings just a little bit more than you did before reading.

Edit #1 (3/7/2022)
There are apparently string functions that weren’t listed on the DevHub documentation, these being string.pack, string.unpack, and string.packsize. I don’t understand binary stuff like this, but I did find a nicely detailed reply about them written by @metatablecatmaid. You can find this reply here.

18 Likes

Very useful resource for newer developers as the DevHub version is a tad bit lacking! Props to you!

6 Likes