I am tryin to convert a table I have with a limit of 16 characters to hex keys and then store those hex keys in another table in the same order as the original string.
I have found a function using some online help which can take a string, split it into each character and assign that character to a space in a table.
So if I write function("Hello World!")
the return of the function would be table= {H, e, l, l, o, , W, o, r, l, d, !)
Now I need to limit this to only accept 16 characters and any more than that are discarded.
The function goes as
local str = "Hello World"
local chars = {}
for c in string.gmatch(str, ".") do
chars[#chars+1] = c
end
How can I limit this to 16 elements in the table?
My second question would be after I create this table, how do I go about changing each element of this table to a hex key and storing it in another table in the same order as the original string?
EDIT1: Thank you luke10000 for suggesting the if char.. method, it works perfectly. Now the next part is to convert this to hex and place it in a table.
I found a function which does this operation but there was no explanation with it at all, I understand some of it but not all. I can only print with this to the console all the hex keys.
function hex_dump(buf)
for byte=1, #buf, 16 do
local chunk = buf:sub(byte, byte+15)
--io.write(string.format('%08X ',byte-1)) -- 0's
chunk:gsub('.', function (c) io.write(string.format('0x%X ',string.byte(c))) end)
io.write(string.rep(' ',3*(16-#chunk)),"\n")
--io.write(' ',chunk:gsub('%c','.'),"\n") -- add the character infront of hex key
end end
for _, chars in ipairs(chars) do
hex_dump(chars) end
I'm not sure how the rest of your post is related to your actual problem.
I am tryin to convert a table I have with a limit of 16 characters to
hex keys and then store those hex keys in another table in the same
order as the original string.
I'm also not sure what you mean with "hex key".
local input = {"H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", "!"}
local output = {}
for i,v in ipairs(input) do
output[i] = string.format("0x%X", v:byte())
if i == 16 then break end
end
print(table.concat(output, ", "))
Regarding your other questions:
local str = "Hello World"
local chars = {}
for c in string.gmatch(str, ".") do
chars[#chars+1] = c
end
How can I limit this to 16 elements in the table?
Simply limit your input string to 16 characters.
for c in str:sub(1,16):gmatch(".") do ...
My second question would be after I create this table, how do I go
about changing each element of this table to a hex key and storing it
in another table in the same order as the original string?
If your actual problem is to get a table of number representations from a string, simply use string.byte
local str = "Hello world! This is a wonderful day.!"
local output = table.pack(str:byte(1, 16))
Related
Does someone know a solution to save the key and the values to an table? My idea does not work because the length of the table is 0 and it should be 3.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
a = {}
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a)
The output is correct.
run for k,v in pairs(a) do print(k,v) end to check the contents of your table.
The problem is the length operator which by default cannot be used to get the number of elements of any table but a sequence.
Please refer to the Lua manual: https://www.lua.org/manual/5.4/manual.html#3.4.7
When t is a sequence, #t returns its only border, which corresponds to
the intuitive notion of the length of the sequence. When t is not a
sequence, #t can return any of its borders. (The exact one depends on
details of the internal representation of the table, which in turn can
depend on how the table was populated and the memory addresses of its
non-numeric keys.)
Only use the length operator if you know t is a sequence. That's a Lua table with integer indexes 1,..n without any gap.
You don't have a sequence as you're using non-numeric keys only. That's why #a is 0
The only safe way to get the number of elements of any table is to count them.
local count = 0
for i,v in pairs(a) do
count = count + 1
end
You can put #Piglet' code in the metatable of a as method __len that is used for table key counting with length operator #.
local newstr = "3 = Hello, 67 = Hi, 2 = Bye"
local a = setmetatable({},{__len = function(tab)
local count = 0
for i, v in pairs(tab) do
count = count + 1
end
return count
end})
for k,v in newstr:gmatch "(%d+)%s*=%s*(%a+)" do
--print(k,v)
a[k] = v
end
print(#a) -- puts out: 3
The output of #a with method __len even is correct if the table holds only a sequence.
You can check this online in the Lua Sandbox...
...with copy and paste.
Like i do.
**It takes Input as a string such as this - 'Nice one'
And Output gives - 4,3 (which is no. Of words in sentence or string)
**
function countx(str)
local count = {}
for i = 1, string.len(str) do
s = ''
while (i<=string.len(str) and string.sub(str, i, i) ~= ' ' ) do
s = s .. string.sub(str, i, i)
i = i+1
end
if (string.len(s)>0) then
table.insert(count,string.len(s))
end
end
return table.concat(count, ',')
end
You can find a simple alternative with your new requirements:
function CountWordLength (String)
local Results = { }
local Continue = true
local Position = 1
local SpacePosition
while Continue do
SpacePosition = string.find(String, " ", Position)
if SpacePosition then
Results[#Results + 1] = SpacePosition - Position
Position = SpacePosition + 1
-- if needed to print the string
-- local SubString = String:sub(Position, SpacePosition)
-- print(SubString)
else
Continue = false
end
end
Results[#Results + 1] = #String - Position + 1
return Results
end
Results = CountWordLength('I am a boy')
for Index, Value in ipairs(Results) do
print(Value)
end
Which gives the following results:
1
2
1
3
def countLenWords(s):
s=s.split(" ")
s=map(len,s)
s=map(str,s)
s=list(s)
return s
The above functions returns a list containing number of characters in each word
s=s.split(" ") splits string with delimiter " " (space)
s=map(len,s) maps the words into length of the words in int
s=map(str,s) maps the values into string
s=list(s) converts map object to list
Short version of above function (all in one line)
def countLenWords(s):
return list(map(str,map(len,s.split(" "))))
-- Localise for performance.
local insert = table.insert
local text = 'I am a poor boy straight. I do not need sympathy'
local function word_lengths (text)
local lengths = {}
for word in text:gmatch '[%l%u]+' do
insert (lengths, word:len())
end
return lengths
end
print ('{' .. table.concat (word_lengths (text), ', ') .. '}')
gmatch returns an iterator over matches of a pattern in a string.
[%l%u]+ is a Lua regular expression (see http://lua-users.org/wiki/PatternsTutorial) matching at least one lowercase or uppercase letter:
[] is a character class: a set of characters. It matches anything inside brackets, e.g. [ab] will match both a and b,
%l is any lowercase Latin letter,
%u is any uppercase Latin letter,
+ means one or more repeats.
Therefore, text:gmatch '[%l%u]+' will return an iterator that will produce words, consisting of Latin letters, one by one, until text is over. This iterator is used in generic for (see https://www.lua.org/pil/4.3.5.html); and on any iteration word will contain a full match of the regular expression.
--encode
function strToBytes(str)
local bytes = { str:byte(1, -1)
for i = 1, #bytes do
bytes[i] = bytes[i] + 100
end
return table.concat(bytes, ',')
end
--decode
function bytesToStr(str)
local function gsub(c)return string.char(c - 100) end
return str:gsub('(%d+),?', gsub) end
implemented :
str = "hello world"
strbyte = strToBytes(str)
bytestr = bytesToStr(strbyte)
print(strbyte)
Output :
204,201,208,208,211,132,219,211,214,208,200
print(bytestr)
Output :
"Hello world"
Hi, I need improving my code above. Actually encode and decode functions is work fine, but I need a little bit change.
I want to make encode functions similar like code above, but, the results is table like below :
{204,201,208,208,211,132,219,211,214,208,200}
Then, same as like my first decode functions, all bytes inside the table should be back to "hello world".
I hope my purpose and explanation above is easy to understand. Thanks in advance for any help and suggestions.
Update explanation :
It is a little bit complicated to explain what is my purposes. But I will try to explain as good as I can.
I am trying to make scripts encoder. Encode functions is in encoder scripts side, and decode function is in encoded scripts side. So I must write concatenate decode function before encoded string.
To clearly my explanation, encoder scripts will load undecode source code.
file = io.open(path, "r")
local data = file:read("*l")
The problem is, table cant concatenate with string.
local data = encode(str)--the result is byte array
local data = "decode("..data..")"
file:write(data)
file:close()
local data = string.dump(load(data),true,true)
My first purpose is to hide some important string, because string.dump result is not hide all string.
My second purpose is, to make an obsfucated code using byteArray.
Any solution or suggestion?
SOLVED
function strToBytes(str)
local byteArray= { str:byte(1, -1) }
for i = 1, #byteArray do
byteArray[i] = byteArray[i] + 100
encoded = '{' ..table.concat(byteArray, ',') .. '}'
end
return "load(string.dump(load(bytesToStr("..encoded.."))))()\n"
end
Thank you so much... 👍
Your code was very close to what you were looking for.
--encode
function strToBytes(str)
local byteArray= { str:byte(1, -1) }
for i = 1, #byteArray do
byteArray[i] = byteArray[i] + 100
end
return '{' .. table.concat(byteArray, ',') .. '}'
end
For the encode I removed the table.concat and now just return the byteArray
--decode
function bytesToStr(byteArray)
local output = "" --initialize output variable
for _,b in ipairs(byteArray) do --use ipairs to preserve order
output = output .. string.char(b - 100) --convert each byte to a char and add to output
end
return output
end
For the decode I use a for loop with ipairs to iterate over each byte and concatenate the values into an output variable.
-- test
str = "hello world!"
strbyte = strToBytes(str)
bytestr = 'return bytesToStr(' .. strbyte .. ')'
strBack = string.dump(load(bytestr),true,true)
print(strbyte)
print(bytestr)
print(load(strBack)())
Test output:
{204,201,208,208,211,132,219,211,214,208,200,133}
return bytesToStr({204,201,208,208,211,132,219,211,214,208,200,133})
hello world!
I am having a table data in string form. Sample is given below:
{"engName1":"HOLDER","validDurPeriod":3,"engName2":"INFORMATION","appStatus":2,"stayExpDate":"01/10/2012","engName3":"","appExpDate":"12/04/2010"}
How can I convert it into a proper table type variable so that I can access keys.I am new to lua and I am not aware if there is any existing method to do so.
There is plenty of JSON parsers available for Lua, for example dkjson:
local json = require ("dkjson")
local str = [[
{
"numbers": [ 2, 3, -20.23e+2, -4 ],
"currency": "\u20AC"
}
]]
local obj, pos, err = json.decode (str, 1, nil)
if err then
print ("Error:", err)
else
print ("currency", obj.currency)
for i = 1,#obj.numbers do
print (i, obj.numbers[i])
end
end
Output:
currency €
1 2
2 3
3 -2023
4 -4
Try this code to start with
J=[[
{"engName1":"HOLDER","validDurPeriod":3,"engName2":"INFORMATION","appStatus":2,"stayExpDate":"01/10/2012","engName3":"","appExpDate":"12/04/2010"}
]]
J=J:gsub("}",",}")
L={}
for k,v in J:gmatch('"(.-)":(.-),') do
L[k]=v
print(k,v)
end
You'll still need to convert some values to number and remove quotes.
Alternatively, you can let Lua do the hard work, if you trust the source string. Just replace the loop by this:
J=J:gsub('(".-"):(.-),','[%1]=%2,\n')
L=loadstring("return "..J)()
I'm able to capitalize the first letter of my string using:
str:gsub("^%l", string.upper)
How can I modify this to capitalize the first letter of every word in the string?
I wasn't able to find any fancy way to do it.
str = "here you have a long list of words"
str = str:gsub("(%l)(%w*)", function(a,b) return string.upper(a)..b end)
print(str)
This code output is Here You Have A Long List Of Words. %w* could be changed to %w+ to not replace words of one letter.
Fancier solution:
str = string.gsub(" "..str, "%W%l", string.upper):sub(2)
It's impossible to make a real single-regex replace because lua's pattern system is simple.
in the alternative answer listed you get inconsistent results with words containing apostrophes:
str = string.gsub(" "..str, "%W%l", string.upper):sub(2)
will capitalize the first letter after each apostrophe irregardless if its the first letter in the word
eg: "here's a long list of words" outputs "Here'S A Long List Of Words"
to fix this i found a clever solution here
utilizing this code:
function titleCase( first, rest )
return first:upper()..rest:lower()
end
string.gsub(str, "(%a)([%w_']*)", titleCase)
will fix any issues caused by that weird bug
function titleCase( first, rest )
return first:upper()..rest:lower()
end
string.gsub(str, "(%a)([%w_']*)", titleCase)
BunchOfText {"Yeppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp"}
I have a feeling I will be returning to this question when I need to put something in proper title case.
Below is the Lua code to do exactly that.
It has the disadvantage of not preserving the original spacing between words but it's good enough for now.
-- Lua is like python in syntax, and barebones like C -_-
function Set (list)
local set = {}
for _, l in ipairs(list) do set[l] = true end
return set
end
function firstToUpper(str)
return (str:gsub("^%l", string.upper))
end
function titlecase(str)
-- We need to break the string into pieces
words = {}
for word in string.gmatch(str, '([^%s]+)') do
table.insert(words, word)
end
-- We need to capitalize anything that is not a:
-- - Article
-- - Coordinating Conjunction
-- - Preposition
-- Thus we have a blacklist of such words
local blacklist = Set {
"at", "but", "by", "down", "for", "from",
"in", "into", "like", "near", "of", "off",
"on", "onto", "out", "over", "past", "plus",
"to", "up", "upon", "with", "nor", "yet",
"so", "the"
}
for index, word in pairs(words) do
if(not (blacklist[word] ~= nil)) then
words[index] = firstToUpper(word)
end
end
-- First and last words are always capitalized
words[1] = firstToUpper(words[1])
words[#words] = firstToUpper(words[#words])
-- Concat elements in list via space character
local result = ""
for index, word in pairs(words) do
result = result .. word
if(index ~= #words) then
result = result .. ' '
end
end
return result
end
print(titlecase("the world"))
print(titlecase("I walked my dog this morning ..."))
print(titlecase("The art of Lua"))
--- Output:
----------------------
--- The World
--- I Walked My Dog This Morning ...
--- The Art of Lua