The following code takes a string and converts it to it's number equivalent. A=1 ... Z=26, while keeping all other characters intact. It formats the string using two delimiters. One for between characters and one for between words. I want to optimize it, and have fixed a lot of redundancy, and slow parts. However, I can't seem to make it any faster. The longest amount of time is taken for decrypting an encrypted string. I would like to optimize both parts.
Suggestions on techniques or code with explanation would be most helpful. This is mostly for me to understand the bottlenecks in Lua logic.
function parseString(str,del1,del2)
local delim1 = del1 or ' '
local delim2 = del2 or '-'
local tab = {}
local sub = ''
local index = 1
local c = ''
local i = 1
while (i > #str and sub == '') == false do
c = str:sub(i,i)
if c == delim2 or c == delim1 or c == '' then
if string.match(sub,'%d') == nil then
tab[index] = sub
index = index + 1
else
tab[index] = string.char(tonumber(sub) + 96)
index = index + 1
end
if c == delim1 then
tab[index] = ' '
index = index + 1
end
sub = ''
else
sub = sub .. c
end
i = i + 1
end
return table.concat(tab)
end
function strToNums(str)
local t = {string.byte(str,1,#str)}
for i,v in ipairs(t) do
if v < 97 and v >= 65then
t[i] = v - 64
else
if v <= 172 and v >= 97then
t[i] = v - 96
else
t[i] = v
end
end
end
return t
end
function formater(del1,del2,arg)
local out = {}
local index = 1
local nDel1 = string.byte(del1)
local nDel2 = string.byte(del2)
for i,v in ipairs(arg) do
if v <= 26 and v >= 1 then
out[index] = tostring(v)
index = index + 1
if i < #arg and arg[i+1] ~= nDel1 then
out[index] = del2
index = index + 1
end
else
if v == 32 then
out[index] = del1
index = index + 1
else
out[index] = string.char(v)
index = index + 1
if i < #arg and arg[i+1] ~= nDel1 then
out[index] = del2
index = index + 1
end
end
end
end
return table.concat(out)
end
function main()
local line = ''
local del1 = ' '
local del2 = '-'
local x = os.clock()
local line2 = ''
local str =''
for i=1,1000 do
str = strToNums("This string'll test my system!")
line = formater(del1,del2,str)
line2 = parseString(line,del1,del2)
end
print(line,line2)
print(string.format("elapsed time: %.10f\n", os.clock() - x))
-- while true do
-- line = io.read()
-- if string.match(line,'%a+') == nil then break end
-- line = formater(del1,del2,strToNums(line))
-- print(line)
-- print(parseString(line,del1,del2))
-- end
end
main()
This is the output that I would expect for the given input:
20-8-9-19 19-20-18-9-14-7-'-12-12 20-5-19-20 13-25 19-25-19-20-5-13-! this string'll test my system!
elapsed time: 0.0880000000
strToNum takes a string and converts it to a table of char values.
Formatter takes two types of delimiters: one for between characters and one for between words. It also takes the table of values generated by strToNum. It takes these values and creates a string with each character separated by one delimiter and each word separated by another.
parseString takes a string and two delimiters. The delimiters are to be checked against. The string is iterated over, and between iterators another sub string is created and added to as long as there is not a delimiter. Each time it runs into a delimiter it adds it to a table. Which is then concatenated at the end. This function takes the most amount of time to run. I think it is because of the using substring, string.char and tonumber.
edit: It certainly became faster. Not quite twice as fast though. I see a lot of the redundancies in my code now. Mine with just encoding
> lua numandstring.lua
20-8-9-19 19-20-18-9-14-7-'-12-12 20-5-19-20 13-25 19-25-19-20-5-13-!
elapsed time: 0.0330000000
new one with just encoding
> lua numandstring.lua
20-8-9-19 19-20-18-9-14-7-'-12-12 20-5-19-20 13-25 19-25-19-20-5-13-!
elapsed time: 0.0280000000
I squeezed out a little more speed with
function encode3(input, wordDelimiter, characterSeparator)
local out = {}
input = input:upper()
local index = 1
local c = input:sub(1,1)
local inputLength = #input
for i=1,inputLength do
local nextc = input:sub(i+1,i+1)
if c == wordDelimiter then
out[index] = c
index = index + 1
else
out[index] = lookup[c] or c
index = index + 1
if i < inputLength and nextc ~= wordDelimiter then
out[index] = characterSeparator
index = index + 1
end
end
c = nextc
end
return table.concat(out)
end
I eliminated calling the table length method repeatedly, because it has to iterate over the whole table. C habits die hard.
> lua numandstring.lua
20-8-9-19 19-20-18-9-14-7-'-12-12 20-5-19-20 13-25 19-25-19-20-5-13-!
elapsed time: 0.0250000000
Also the calls to the first sub make no difference. Sub is called the same amount of times either way.
function x() print('x') return 10 end for i=1,x() do end
Note how many timesx
is called. \$\endgroup\$