Strings and Pattern Matching
By the end of this lesson you'll format and slice text with the string library, search and replace with find , match , gmatch , and gsub , and wield Lua's own lightweight pattern system — character classes, anchors, quantifiers, and captures — to validate and extract data without ever reaching for a regex engine.
Learn Strings and Pattern Matching in our free Lua course — an interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Lua course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Think of a Lua pattern as a cookie cutter pressed into a sheet of dough. The cutter's shape — letters here, digits there, a gap of whitespace — decides exactly which pieces of text pop out. It is a simpler tool than a full regex Swiss-army knife: fewer settings, but lighter, faster, and built right into the language. Once you learn the handful of shapes ( %a , %d , %s , %w ) and the quantifiers that stretch them, you can stamp structured data out of almost any messy string.
1. The String Library: Length, Slicing & Case
Lua bundles its text tools in the string library, and every string can call them as methods with a colon ( name:upper() is the same as string.upper(name) ). You measure length with # or string.len , pull out slices with string.sub (1-based and inclusive, with negatives counting from the end), change case with upper / lower , and repeat text with rep . Strings are immutable — every one of these returns a brand-new string. Read and run this example.
2. Building Strings with string.format
string.format is the cleanest way to stitch values into text. It works just like C's printf : a format string holds % placeholders that get filled by the arguments — %s for strings, %d for integers, %.2f for a float with two decimals, %x for hex, and %q for a safely quoted string. You can add width and alignment ( %5d , %-5d ), and write %% for a literal percent sign. It beats long chains of .. concatenation for anything with numbers.
Your turn. Finish the receipt line with string.format and slice a name with string.sub . Fill in the blanks marked ___ and compare with the expected output.
3. Searching & Replacing: find, match, gmatch, gsub
Four functions do the heavy lifting. string.find returns the positions of a match (pass true as a fourth argument for a plain, non-pattern search). string.match returns the matched text or its captures. string.gmatch hands back an iterator so you can loop over every match. And string.gsub performs a global substitution, returning the new string plus a count of how many replacements it made. Learn these four and you can parse almost anything.
4. Lua Patterns (Not Regex)
The magic inside those four functions is the Lua pattern , a small system that is not a full regular expression engine. Classes start with a percent sign: %a letters, %d digits, %s whitespace, %w alphanumerics (uppercase versions negate). Quantifiers follow the item they repeat: * zero-or-more, + one-or-more, - lazy zero-or-more, ? optional. Anchors ^ and $ tie a match to the start or end of the string. Parentheses () create captures , and the magic characters ^ $ ( ) % . [ ] * + - ? must be escaped with % .
Now you try patterns. Capture the key and value from a key=value line, then count words with gmatch . Fill in the two blanks:
No blanks this time — just a brief and an outline. You'll combine gmatch with a "not a comma" pattern and a trimming gsub . Build it, run it, and check your output against the example in the comments.
Practice quiz
Which function returns a formatted string using % placeholders?
- string.format
- string.printf
- string.template
- string.fill
Answer: string.format. string.format works like C's printf, returning a new string built from the format and arguments.
What does the # operator return for a string?
- The number of words
- Its memory address
- Its byte length
- Its first character
Answer: Its byte length. On a string, # gives the length in bytes, the same value string.len returns.
Which pattern class matches a single letter (a-z, A-Z)?
- %s
- %a
- %w
- %d
Answer: %a. %a matches any alphabetic character; %d is digits, %s is whitespace, %w is alphanumerics.
What does string.gsub return in addition to the new string?
- The original string
- Nothing else
- The matched captures
- The number of substitutions made
Answer: The number of substitutions made. gsub returns the modified string plus a count of how many replacements it performed.
Which function is designed to iterate over ALL matches in a loop?
- string.gmatch
- string.find
- string.match
- string.sub
Answer: string.gmatch. string.gmatch returns an iterator yielding each successive match, ideal for a for loop.
In Lua patterns, what does the anchor ^ mean at the start of a pattern?
- Repeat zero or more
- Match only at the beginning of the string
- Negate the class
- Match the end of the string
Answer: Match only at the beginning of the string. A leading ^ anchors the match to the start of the subject string.
How do you match a literal dot '.' in a Lua pattern?
- Wrap it in quotes
- Dots are always literal
- Use .. instead
- Write %.
Answer: Write %.. '.' is the magic 'any character' class, so escape it with % to match a literal period: %.
Which quantifier means 'zero or one' (optional) in Lua patterns?
- *
- +
- ?
- -
Answer: ?. ? matches the previous class zero or one time, making it optional.
What do parentheses () do inside a Lua pattern?
- Group for alternation
- Define a capture to return
- Escape magic characters
- Mark an anchor
Answer: Define a capture to return. Parentheses create captures; the captured substrings are returned by find, match, and gmatch.
Are Lua patterns the same as POSIX or PCRE regular expressions?
- No, they are a simpler distinct system
- Only in Lua 5.4
- Only with the regex library
- Yes, fully compatible
Answer: No, they are a simpler distinct system. Lua patterns are their own lightweight system, not regex; there is no alternation | or full regex backtracking.