string.gsub, безусловно. Забудь про какие-то жутчайшие костыли с string.find и прочим. Гсаб тут просто рулит и педали от пола не отрывает.
Он может поменять одно слово на другое.
string.gsub("abc", "a", "d") == "dbc"
Он может поменять один паттерн на что-то другое.
string.gsub("hello world", "%w+", [["%1"]]) == [["hello" "world"]]
Он может поменять один паттерн на табличное значение.
local greek = {
l = "λ",
o = "ο",
g = "γ",
i = "ι",
k = "κ",
e = "ή",
}
string.gsub([[logic derives from Ancient Greek $l$o$g$i$k$e]], "$(%w+)", greek) == "logic derives from Ancient Greek λογική"
И самое крутое: он может менять один паттерн по функции, вызывая её для каждого матча.
string.gsub([[breaking news: title case considered stupid]], "(%w)(%w*)", function(head, tail)
return head:upper() .. tail
end) == [[Breaking News: Title Case Considered Stupid]]
Читайте подробнее вот где-то тут.