Hi folks.
In my game I need to replace a single letter in a string with another letter.
I have code to do this, but I’d like something a little more elegant and hopefully faster.
( Motivation: When I do this operation, I may do it hundreds of times in a row.)
local function replaceAt( str, at, with ) if( at \< 1 or at \> string.len( str ) ) then return str elseif( at == 1 ) then return with .. strSub( str, at+1, string.len(str) ) elseif( at == string.len( str ) ) then return strSub( str, 1, at-1 ) .. with end return strSub( str, 1, at-1 ) .. with .. strSub( str, at+1, string.len(str) ) end
If you’re a Lua wizard and have a better solution, please share.
Assuming strSub() is just a cached string.sub(), you can dispense with the second and third checks altogether, since string.sub(s, 1, 0) and string.sub(s, #s + 1, #s) will both give you “”.
For that matter, the negative indices are perfectly legitimate so you might consider making your original check something like
if math.abs(at) \> #str then
What are you using the strings for? If you do this constantly, hundreds of times in a row the bigger hidden cost might be all the created garbage you constantly create as each changed string is a new immutable sequence/object Lua has to hash and add into it’s pool of interned strings.
Hi roaminggamer,
-
Consider change data representations. Use table of characters instead of string.
-
Try
local pattern = { } for i=1, 100 do pattern[#pattern + 1] = ‘^(.-’… string.rep( ‘.’, i - 1 ) … ‘)(.)’ end local function replaceAt( str, at, with ) --return at < 1 and str or str:gsub( ‘^(.-’ … string.rep( ‘.’, at - 1 ) … ‘)(.)’, ‘%1’ … with ) – OR return at < 1 and str or str:gsub( pattern[at], ‘%1’ … with ) end
I’m not sure how fast it is. You need check that yourself.
Have a nice day:)
ldurniat
the smallest i could get was:
local function replaceAt( str, at, with ) return string.sub(str, 1, at-1 )..with..(string.sub(str, at+1, string.len(str))) end
this is only useful if you control the “at” variable and is not a user that can break your code.
if you can’t control the “at” variable:
local function replaceAt( str, at, with ) local length=string.len(str) -- don't know if #str is faster, but i guess not. if( at \< 1 or at \> length) then return str else return string.sub(str, 1, at-1 )..with..(string.sub(str, at+1, length)) end end
to use:
local stringExample="Hello World!" local newString=replaceAt(stringValue, 2, "X") print (newString)
*edit*
the fastest version with protection i can build is:
function replaceAt(str, at, with) return ((at \< 1) or (at \> string.len(str))) and str or string.sub(str, 1, at-1 )..with..string.sub(str, at+1) end
regards,
Carlos.
Assuming strSub() is just a cached string.sub(), you can dispense with the second and third checks altogether, since string.sub(s, 1, 0) and string.sub(s, #s + 1, #s) will both give you “”.
For that matter, the negative indices are perfectly legitimate so you might consider making your original check something like
if math.abs(at) \> #str then
What are you using the strings for? If you do this constantly, hundreds of times in a row the bigger hidden cost might be all the created garbage you constantly create as each changed string is a new immutable sequence/object Lua has to hash and add into it’s pool of interned strings.
Hi roaminggamer,
-
Consider change data representations. Use table of characters instead of string.
-
Try
local pattern = { } for i=1, 100 do pattern[#pattern + 1] = ‘^(.-’… string.rep( ‘.’, i - 1 ) … ‘)(.)’ end local function replaceAt( str, at, with ) --return at < 1 and str or str:gsub( ‘^(.-’ … string.rep( ‘.’, at - 1 ) … ‘)(.)’, ‘%1’ … with ) – OR return at < 1 and str or str:gsub( pattern[at], ‘%1’ … with ) end
I’m not sure how fast it is. You need check that yourself.
Have a nice day:)
ldurniat
the smallest i could get was:
local function replaceAt( str, at, with ) return string.sub(str, 1, at-1 )..with..(string.sub(str, at+1, string.len(str))) end
this is only useful if you control the “at” variable and is not a user that can break your code.
if you can’t control the “at” variable:
local function replaceAt( str, at, with ) local length=string.len(str) -- don't know if #str is faster, but i guess not. if( at \< 1 or at \> length) then return str else return string.sub(str, 1, at-1 )..with..(string.sub(str, at+1, length)) end end
to use:
local stringExample="Hello World!" local newString=replaceAt(stringValue, 2, "X") print (newString)
*edit*
the fastest version with protection i can build is:
function replaceAt(str, at, with) return ((at \< 1) or (at \> string.len(str))) and str or string.sub(str, 1, at-1 )..with..string.sub(str, at+1) end
regards,
Carlos.