Your call is basically taking the string value 10 and converting it to a number in base 5 which results in the number 5. This happens because tonumber can take more than 1 parameter, the optional second paramater base
When called with base, then e must be a string to be interpreted as an integer numeral in that base. The base may be any integer between 2 and 36, inclusive.
Lua 5.4 Reference Manual - tonumber (e [, base])
So what you are doing is calling tonumber by passing ALL the results from gsub this include the second return value which indicates the number of matches that happened.
Returns a copy of s in which all (or the first n, if given) occurrences of the pattern (see §6.4.1) have been replaced by a replacement string specified by repl, which can be a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred. The name gsub comes from Global SUBstitution.
Lua 5.4 Reference Manual - string.gsub (s, pattern, repl [, n])
There are a few ways to fix this, specify the base in your tonubmer call
print(tonumber(string.gsub("spawn10", "%D", ""),10))
or as you discovered wrapping the gsub call in (
print(tonumber((string.gsub("spawn10", "%D", ""))))
Both of these accomplish the same thing by discarding all but the first value returned by gsub.
This mechanism is described in Lua 5.4 Reference Manual: 3.4 – Expressions
If a function call is used as a statement (see §3.3.6), then its return list is adjusted to zero elements, thus discarding all returned values. If an expression is used as the last (or the only) element of a list of expressions, then no adjustment is made (unless the expression is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, either discarding all values except the first one or adding a single nil if there are no values.