Lua every 4 characters in string insert a value - lua

So I have a string that every 4 characters I need to insert a value like so.
local string = "24029400001000000000000000000000"
--insert : every 4 chars
--output
--2402:9400:0010:0000:0000:0000:0000:0000
The output i am looking for is 2402:9400:0010:0000:0000:0000:0000:0000
function string.chunk( str, n )
local k, t
t= { }
for k in str:gmatch( string.rep( ".", n ) ) do
table.insert( t, k )
end
return t
end
x = "24029400001000000000000000000000"
x_new = ""
for k, v in ipairs( x:chunk( 4 ) ) do
v = v .. ":"
x_new = x_new .. v
end
print(x_new)
--problem is 2402:9400:0010:0000:0000:0000:0000:0000: the : on the end of string

Possible solution:
<script src="https://github.com/fengari-lua/fengari-web/releases/download/v0.1.4/fengari-web.js"></script>
<script type="application/lua">
local s = "24029400001000000000000000000000"
s = s:gsub('....','%1:'):gsub(':$','')
print(s)
</script>

Related

String with Numbers to Table

How can i transform this following string:
string = "1,2,3,4"
into a table:
table = {1,2,3,4}
thanks for any help ;)
Let Lua do the hard work:
s="1,2,3,4"
t=load("return {"..s.."}")()
for k,v in ipairs(t) do print(k,v) end
Below is the code adapted from the Scribunto extension to MediaWiki. It allows to split strings on patterns that can be longer than one character.
-- Iterator factory
function string:gsplit (pattern, plain)
local s, l = 1, self:len()
return function ()
if s then
local e, n = self:find (pattern, s, plain)
local ret
if not e then
ret = self:sub (s)
s = nil
elseif n < e then
-- Empty separator!
ret = self:sub (s, e)
if e < l then
s = e + 1
else
s = nil
end
else
ret = e > s and self:sub (s, e - 1) or ''
s = n + 1
end
return ret
end
end, nil, nil
end
-- Split function that returns a table:
function string:split (pattern, plain)
local ret = {}
for m in self:gsplit (pattern, plain) do
ret [#ret + 1] = m
end
return ret
end
-- Test:
local str = '1,2, 3,4'
print ('table {' .. table.concat (str:split '%s*,%s*', '; ') .. '}')
You can use gmatch and the pattern (%d+) to create an iterator and then populate the table.
local input = "1,2,3,4"
local output = {}
for v in input:gmatch("(%d+)") do
table.insert(output, tonumber(v))
end
for _,v in pairs(output) do
print(v)
end
The pattern (%d+) will capture any number of digits(0-9).
This is a narrow solution, it does not handle blank entries such as
input = "1,2,,4"
output = {1,2,4}
It also does not care what the delimitator is, or if it is even consistent for each entry.
input = "1,2 3,4"
output = {1,2,3,4}
Reference:
Lua 5.3 Manual, Section 6.4 – String Manipulation: string.gmatch
FHUG: Understanding Lua Patterns

'end' expected near '<eof>' in Lua

I have tried to realize adding numbers in lua:
local Calculator = {};
function Calculator.get( frame )
local new_args = str._getParameters( frame.args, { 'f', 'o', 's' } );
local f = tonumber( new_args['f'] ) or 1;
local o = ( new_args['o'] ) or "";
local s = tonumber( new_args['s'] ) or 1;
Calculator.ret(first, second, operation);
end
function Calculator.ret (f, o, s)
if(o == "+") then return f+s;
end
return Calculator
Even if place a end in end, error doesn't disappear.
function Calculator.ret (f, o, s)
if(o == "+") then return f+s end
end ^----------------- here
if in Lua always has to have an end (kinda unlike {} for ifs in C-like languages).

Can I create a gmatch pattern that returns a variadic number of values?

I need to iterate over some pairs of strings in a program that I am writing. Instead of putting the string pairs in a big table-of-tables, I am putting them all in a single string, because I think the end result is easier to read:
function two_column_data(data)
return data:gmatch('%s*([^%s]+)%s+([^%s]+)%s*\n')
end
for a, b in two_column_data [[
Hello world
Olá hugomg
]] do
print( a .. ", " .. b .. "!")
end
The output is what you would expect:
Hello, world!
Olá, hugomg!
However, as the name indicates, the two_column_data function only works if there are two exactly columns of data. How can I make it so it works on any number of columns?
for x in any_column_data [[
qwe
asd
]] do
print(x)
end
for x,y,z in any_column_data [[
qwe rty uio
asd dfg hjk
]] do
print(x,y,z)
end
I'm OK with using lpeg for this task if its necessary.
function any_column_data(data)
local f = data:gmatch'%S[^\r\n]+'
return
function()
local line = f()
if line then
local row, ctr = line:gsub('%s*(%S+)','%1 ')
return row:match(('(.-) '):rep(ctr))
end
end
end
Here is an lpeg re version
function re_column_data(subj)
local t, i = re.compile([[
record <- {| ({| [ %t]* field ([ %t]+ field)* |} (%nl / !.))* |}
field <- escaped / nonescaped
nonescaped <- { [^ %t"%nl]+ }
escaped <- '"' {~ ([^"] / '""' -> '"')* ~} '"']], { t = '\t' }):match(subj)
return function()
local ret
i, ret = next(t, i)
if i then
return unpack(ret)
end
end
end
It basicly is a redo of the CSV sample and supports quoted fields for some nice use-cases: values with spaces, empty values (""), multi-line values, etc.
for a, b, c in re_column_data([[
Hello world "test
test"
Olá "hug omg"
""]].."\tempty a") do
print( a .. ", " .. b .. "! " .. (c or ''))
end
local function any_column_data( str )
local pos = 0
return function()
local _, to, line = str:find("([^\n]+)\n", pos)
if line then
pos = to
local words = {}
line:gsub("[^%s]+", function( word )
table.insert(words, word)
end)
return table.unpack(words)
end
end
end
Outer loop returns lines, and inner loop returns words in line.
s = [[
qwe rty uio
asd dfg hjk
]]
for s in s:gmatch('(.-)\n') do
for s in s:gmatch('%w+') do
io.write(s,' ')
end
io.write('\n')
end

Formatting a table in Lua with string.gsub

The following code formats a table into a printable string, but I feel like this can be done a lot easier.
function printFormat(table)
local str = ""
for key, value in pairs(table) do
if value == 1 then
str = str .. string.gsub(value, 1, "A, ") -- Replaces 1 with A
elseif value == 2 then
str = str .. string.gsub(value, 2, "B, ") -- Replaces 2 with B
elseif value == 3 then
str = str .. string.gsub(value, 3, "C, ") -- Replaces 3 with C
elseif value == 4 then
str = str .. string.gsub(value, 4, "D, ") -- Replaces 4 with D
end
end
str = string.sub(str, 1, #str - 2) -- Removes useless chars at the end (last comma and last whitespace)
str = "<font color=\"#FFFFFF\">" .. str .. "</font>" -- colors the string
print(str)
end
local myTable = {1,4,3,2,3,2,1,3,4,2,2,...}
printFormat(myTable)
Is there a way to use a oneliner instead of having to loop through every index and make changes?
Or make the code more compact?
You can use a helper table to replace the multiple if statement:
local chars = {"A", "B", "C", "D"}
for _, v in ipairs(t) do
str = str .. chars[v] .. ", "
end
Or, if there are more than 1 to 4, try this:
for _, v in ipairs(t) do
str = str .. string.char(string.byte('A') + v) .. ", "
end
Use table.concat.
string.gsub can perform replacement using a replacement table.
Don't use names like table for your own variables.
Therefore:
function printFormat( tInput )
local sReturn = table.concat( tInput, ', ' )
sReturn = sReturn:gsub( '%d', {['1'] = 'A', ...} ) -- update table accordingly
return '<font color="#FFFFFF">' .. str .. "</font>"
end
and, for one liner:
return '<font color="#FFFFFF">' .. ( table.concat(tInput, ', ') ):gsub( '%d', {['1'] = 'A', ...} )

Operator overloading not working

While reading Programming in Lua, I tried this example given in the book for operator overloading
Set = {}
mt = {}
mt.__add = Set.union
--create a new set with the values of the given list
function Set.new (l)
local set = {}
setmetatable (set, mt)
for _, v in ipairs (l) do
set [v] = true
end
return set
end
function Set.union (a, b)
local result = Set.new {}
for k in pairs (a) do result [k] = true end
for k in pairs (b) do result [k] = true end
return result
end
function Set.intersection (a, b)
local result = Set.new {}
for k in pairs (a) do result [k] = b[k] end
return result
end
function Set.tostring (set)
local l = {}
for e in pairs (set) do
l[#l + 1] = e
end
return "{" .. table.concat (l, ", ") .. "}"
end
function Set.print (s)
print (Set.tostring (s))
end
s1 = Set.new {10, 20, 30, 50}
s2 = Set.new {30, 1}
Set.print (s1)
Set.print (s2)
s3 = s1 + s2
Set.print (s3)
But with the latest lua for windows I am getting the following error
lua: C:\meta.lua:47: attempt to perform arithmetic on global 's1' (a table value)
stack traceback:
C:\meta.lua:47: in main chunk
[C]: ?
{30, 10, 20, 50}
{1, 30}
You are making this assignment too early:
mt.__add = Set.union
because Set.union is not initialized yet.
Move this below Set.union and it will work.
For the same reason, if you assign mt.__mul, this should be below Set.intersection
You need to define mt as a suitable metatable:
mt = { __add = Set.union, __mul = Set.intersection, __tostring = Set.tostring }

Resources