You can use the string.gsub function with the pattern "[^%w%s]" and the replacement "%%%1".
In the pattern, we used the square brackets to match anything inside them which are not characters that are alphanumeric (%w) or characters that are spaces (%s).
In the replacement, we escaped the percentage magic character by writing it twice and we used it as a magic character combined with “1” to insert the captured character back.
Here is the demo.
local str = "Hello! I'm *!(("
local transformed = string.gsub(str, "[^%w%s]", "%%%1")
print(transformed) -- output: "Hello%! I%'m %*%!%(%("