Seeking More Optimal Solution - Replace single character at position in string

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,

  1. Consider change data representations. Use table of characters instead of string. 

  2. 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,

  1. Consider change data representations. Use table of characters instead of string. 

  2. 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.