luaguides

string.gsub

string.gsub(s, pattern, repl [, n])

string.gsub (global substitute) walks a string, replacing each match of a Lua pattern with repl. It returns the new string and the count of substitutions made. The replacement can be a literal string with %n back-references, a table keyed by capture, or a function called for every match.

Signature

local result, count = string.gsub(s, pattern, repl [, n])
  • s , the subject string.
  • pattern , a Lua pattern (the same syntax string.find and string.match accept).
  • repl , the replacement: a string, a table, or a function.
  • n , optional cap on substitutions. Without it, every match is replaced.

String replacement with back-references

Inside a string repl, %0 is the whole match and %1, %2, … are the captures:

local out, n = string.gsub("hello world", "(%w+) (%w+)", "%2 %1")
print(out, n)   --> world hello   1

Use %% to insert a literal percent sign.

Limiting the number of replacements

Pass n to stop after the first few matches:

string.gsub("aaaa", "a", "b", 2)   --> "bbaa"   2

Table replacement

When repl is a table, the first capture (or the whole match when there is none) is used as the key. The value becomes the replacement. A nil or false value leaves the match untouched.

local vars = {name = "Ada", role = "engineer"}
local tmpl = "Hello ${name}, you are a ${role}."
print((tmpl:gsub("%${(%w+)}", vars)))
-- Hello Ada, you are a engineer.

Function replacement

When repl is a function, it’s called for each match with the captures (or the whole match) as arguments. The return value is converted to a string and used as the replacement. nil or false keeps the original match.

local function upper_word(w) return w:upper() end
print((string.gsub("hello world", "%w+", upper_word)))
-- HELLO WORLD

This is the cleanest way to do per-match transformations:

local function envvar(name)
  return os.getenv(name) or ""
end
local cmd = "deploy ${HOME}/app"
print((cmd:gsub("%${(%w+)}", envvar)))
-- deploy /home/ada/app

Method syntax

("text"):gsub(...) is the same as string.gsub("text", ...):

local trimmed = ("  hello  "):gsub("^%s+", ""):gsub("%s+$", "")

Note that gsub returns two values; if you chain with :gsub(...) again on the result, wrap in parentheses or capture both returns.

Capture replacement gotchas

  • %0 is the entire match , handy when you want to keep the match and wrap it.
  • %1 through %9 reference captures; if you write %2 but only have one capture, Lua raises an error.
  • The replacement string is not a regex, so \n is just two characters; use "\n" (Lua escape) for a newline.

Counting without replacing

Because gsub returns the substitution count as its second value, it doubles as a match counter:

local _, vowels = ("supercalifragilistic"):gsub("[aeiou]", "")
print(vowels)   --> 8

See also