Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

Seeking More Optimal Solution - Replace single character at position in string
Started by roaminggamer Jul 25 2018 04:02 PM

- - - - -
4 replies to this topic
[TOPIC CONTROLS]
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
  • Corona Geek

  • 6,923 posts
  • Corona SDK

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.

Edited by roaminggamer, 25 July 2018 - 05:25 PM.


[TOPIC: post.html]
#2

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 744 posts
  • Corona SDK

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


[TOPIC: post.html]
#3

Michael Flad

[GLOBAL: userInfoPane.html]
Michael Flad
  • Contributor

  • 139 posts
  • Corona SDK

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.



[TOPIC: post.html]
#4

ldurniat

[GLOBAL: userInfoPane.html]
ldurniat
  • Contributor

  • 354 posts
  • Corona SDK

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


Edited by ldurniat, 26 July 2018 - 10:24 AM.


[TOPIC: post.html]
#5

carloscosta

[GLOBAL: userInfoPane.html]
carloscosta
  • Contributor

  • 586 posts
  • Corona SDK

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.


Edited by carloscosta, 03 August 2018 - 08:06 AM.



[topic_controls]
[/topic_controls]