Parsing file in Lua for specific value in table - parsing

I am very new to lua programming and am trying to parse a local file on my pc and then save certain elements of the table/array into strings.
I have been able to get all the data and print each line of the file, except I am having problems when trying to get specific value and save them into strings or just print a certain line. Any help would be greatly appreciated.
Here is my code sample:
function file_exists(file)
local f = io.open(file, "rb")
if f then f:close() end
return f ~= nil
end
function lines_from(file)
if not file_exists(file) then return {} end
lines = {}
for line in io.lines(file) do
lines[#lines + 1] = line
end
return lines
end
local file = 'Stats.txt'
local lines = lines_from(file)
for k,v in pairs(lines) do
print('line[' .. k .. ']', v)
end

Your code works as expected. I copied the code to a file named temp.lua. Here is the output:
line[1] function file_exists(file)
line[2] local f = io.open(file, "rb")
line[3] if f then f:close() end
line[4] return f ~= nil
line[5] end
line[6]
line[7]
line[8] function lines_from(file)
line[9] if not file_exists(file) then return {} end
line[10] lines = {}
line[11] for line in io.lines(file) do
line[12] lines[#lines + 1] = line
line[13] end
line[14] return lines
line[15]
line[16] end
line[17]
line[18] local file = 'temp.lua'
line[19] local lines = lines_from(file)
line[20]
line[21] for k,v in pairs(lines) do
line[22] print('line[' .. k .. ']', v)
line[23] end

Related

(Lua) How do I break a string into entries on a table?

So I want to take an input like R U R' U' and turn it into a table that contains
R
U
R'
U'
I haven't found an example of code that worked. I have tried this solution from codegrepper, and it didn't work. I have not come up with anything else in my head but my general program, which is supposed to take an input like R and find its place in a table. If R is 1, then it will take the value 1 from another table, which will have the r^ as value 1. Then it will do this with the rest and print it when it is done. So if there is an optimization with this that could make it all quicker than I would like to see it. Thanks and goodbye.
function split(str, pat)
local t = {}
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then table.insert(t, cap) end
last_end = e + 1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
then split it with split(var," ")
local myString = "R U R' U'"
local myTable = {}
for e in string.gmatch(myString, "%S+") do
table.insert(myTable, e)
end
Lua Users Wiki
s:gmatch(pattern)
This returns a pattern finding iterator. The iterator will search
through the string passed looking for instances of the pattern you
passed.
First you need to match all the space-separated parts. You can do this using gmatch. Then you can insert these parts as keys in a hash table, the value being the one-indexed index of the occurrence:
local str = "R U R' U'"
local index = 1
local last_occurrence = {}
for match in str:gmatch"%S+" do
last_occurrence[match] = index
index = index + 1
end
Now you can use your "other table" to obtain the value in constant time:
local other_table = {"r^"}
local value = other_table[last_occurrence.R] -- "r^"

find all possible combination of these two sets of items? Lua

I see similar answers to this question given in different programming languages like Haskell and Python but all of them use build-in functionality that Lua doesn't have, so please don't mark this question as duplicate.
Let's say i have two tables like bellow:
table1 = {A,B,C}
table2 = {D,E,F}
I would like to find all unique ways of matching the items from two tables, the answer should be (in informal notation):
AD,BE,CF
AD,BF,CE
AE,BD,CF
AE,BF,CD
AF,BD,CE
AF,BE,CD
so the answer will store in a table that table[1] would be {{A, D}, {B, E}, {C, F}} and so on.
tables length can be anything but both will be the same size.
we can get all shuffles via induction (not the fastest way, but pretty easy to write/understand)
local function deepcopy(orig)
local copy
if type(orig) == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[deepcopy(orig_key)] = deepcopy(orig_value)
end
setmetatable(copy, deepcopy(getmetatable(orig)))
else
copy = orig
end
return copy
end
local function get_shuffles(N)
if N == 1 then
return {{1}}
end
local shuffles = get_shuffles(N-1)
local result = {}
for index = 1, #shuffles do
local shuffle = shuffles[index]
for position = 1, #shuffle do
local new_shuffle = deepcopy(shuffle)
table.insert(new_shuffle, position, N)
table.insert(result, new_shuffle)
end
local new_shuffle = deepcopy(shuffle)
table.insert(new_shuffle, N)
table.insert(result, new_shuffle)
end
return result
end
table1 = {"A", "B", "C"}
table2 = {"D","E", "F"}
assert(#table1 == #table2)
local result = {}
local shuffles = get_shuffles(#table1)
for index = 1, #shuffles do
local shuffle = shuffles[index]
local part = {}
for i = 1, 3 do
table.insert(part, {})
table.insert(part[i], table1[i])
table.insert(part[i], table2[shuffle[i]])
end
table.insert(result, part)
end
for index = 1, #result do
print(result[index][1][1], result[index][1][2], result[index][2][1], result[index][2][2], result[index][3][1], result[index][3][2])
end
function get_all_combinations(arr1, arr2)
local n, e, all_comb = #arr1, {}, {}
for j = 1, n do
e[j] = arr2[j]
end
local function generate(m)
if m <= 1 then
local comb = {}
all_comb[#all_comb + 1] = comb
for j = 1, n do
comb[j] = arr1[j]..e[j] -- it should be {arr1[j], e[j]} to fulfill your requirements
end
else
for j = 1, m do
generate(m - 1)
local k = j < m and m % 2 == 1 and 1 or j
e[k], e[m] = e[m], e[k]
end
end
end
generate(n)
return all_comb
end
for i, v in ipairs(get_all_combinations({"A", "B", "C"}, {"D", "E", "F"})) do
print(i, table.concat(v, ";"))
end
An alternate way of doing it is with the following code. This was written to help with a game (Typeshift) to discover all possible combinations of variable groups of letters. I've modified it to fit your example, though.
-- table array: { {1, 2}, {3, 4}, {5, 6} }
-- Should return { 135, 136, 145, 146, 235, 236, 245, 246 }
--
-- This uses tail recursion so hopefully lua is smart enough not to blow the stack
function arrayCombine(tableArray)
-- Define the base cases
if (tableArray == nil) then
return nil
elseif (#tableArray == 0) then
return {}
elseif (#tableArray == 1) then
return tableArray[1]
elseif (#tableArray == 2) then
return arrayCombine2(tableArray[1], tableArray[2])
end -- if
-- We have more than 2 tables in the input parameter. We want to pick off the *last*
-- two arrays, merge them, and then recursively call this function again so that we
-- can work our way up to the front.
local lastArray = table.remove(tableArray, #tableArray)
local nextToLastArray = table.remove(tableArray, #tableArray)
local mergedArray = arrayCombine2(nextToLastArray, lastArray)
table.insert(tableArray, mergedArray)
return arrayCombine(tableArray)
end -- arrayCombine
function arrayCombine2(array1, array2)
local mergedArray = {}
for _, elementA in ipairs(array1) do
for _, elementB in ipairs(array2) do
table.insert(mergedArray, elementA .. elementB)
end -- for
end -- for
return mergedArray
end -- arrayCombine2
-- You can set it up this way:
combinedArray = {}
table.insert(combinedArray, {"A", "B", "C"})
table.insert(combinedArray, {"D", "E", "F"})
for i,v in ipairs(arrayCombine(combinedArray)) do
print(i,v)
end
-- Or go this way, which may be somewhat cleaner:
for i,v in ipairs(arrayCombine({{"A", "B", "C"}, {"D", "E", "F"}})) do
print(i,v)
end
Either way, it produces the results you're looking for.

Lua Script Looping Forever

I am using an opensource tool called NeuralTalk2 that essentially takes several pictures and outputs a caption it thinks describes the picture. There is a lua script in there that looks like this:
--[[
Same as DataLoader but only requires a folder of images.
Does not have an h5 dependency.
Only used at test time.
]]--
local utils = require 'misc.utils'
require 'lfs'
require 'image'
local DataLoaderRaw = torch.class('DataLoaderRaw')
function DataLoaderRaw:__init(opt)
local coco_json = utils.getopt(opt, 'coco_json', '')
-- load the json file which contains additional information about the dataset
print('DataLoaderRaw loading images from folder: ', opt.folder_path)
self.files = {}
self.ids = {}
if string.len(opt.coco_json) > 0 then
print('reading from ' .. opt.coco_json)
-- read in filenames from the coco-style json file
self.coco_annotation = utils.read_json(opt.coco_json)
for k,v in pairs(self.coco_annotation.images) do
local fullpath = path.join(opt.folder_path, v.file_name)
table.insert(self.files, fullpath)
table.insert(self.ids, v.id)
end
else
-- read in all the filenames from the folder
print('listing all images in directory ' .. opt.folder_path)
local function isImage(f)
local supportedExt = {'.jpg','.JPG','.jpeg','.JPEG','.png','.PNG','.ppm','.PPM'}
for _,ext in pairs(supportedExt) do
local _, end_idx = f:find(ext)
if end_idx and end_idx == f:len() then
return true
end
end
return false
end
local n = 1
for file in paths.files(opt.folder_path, isImage) do
local fullpath = path.join(opt.folder_path, file)
table.insert(self.files, fullpath)
table.insert(self.ids, tostring(n)) -- just order them sequentially
n=n+1
end
end
self.N = #self.files
print('DataLoaderRaw found ' .. self.N .. ' images')
self.iterator = 1
end
function DataLoaderRaw:resetIterator()
self.iterator = 1
end
--[[
Returns a batch of data:
- X (N,3,256,256) containing the images as uint8 ByteTensor
- info table of length N, containing additional information
The data is iterated linearly in order
--]]
function DataLoaderRaw:getBatch(opt)
local batch_size = utils.getopt(opt, 'batch_size', 5) -- how many images get returned at one time (to go through CNN)
-- pick an index of the datapoint to load next
local img_batch_raw = torch.ByteTensor(batch_size, 3, 256, 256)
local max_index = self.N
local wrapped = false
local infos = {}
for i=1,batch_size do
local ri = self.iterator
local ri_next = ri + 1 -- increment iterator
if ri_next > max_index then ri_next = 1; wrapped = true end -- wrap back around
self.iterator = ri_next
-- load the image
local img = image.load(self.files[ri], 3, 'byte')
img_batch_raw[i] = image.scale(img, 256, 256)
-- and record associated info as well
local info_struct = {}
info_struct.id = self.ids[ri]
info_struct.file_path = self.files[ri]
table.insert(infos, info_struct)
end
local data = {}
data.images = img_batch_raw
data.bounds = {it_pos_now = self.iterator, it_max = self.N, wrapped = wrapped}
data.infos = infos
return data
end
This code does many things, but please pay attention to the __init function that begins at line 13:
function DataLoaderRaw:__init(opt)
local coco_json = utils.getopt(opt, 'coco_json', '')
-- load the json file which contains additional information about the dataset
print('DataLoaderRaw loading images from folder: ', opt.folder_path)
self.files = {}
self.ids = {}
if string.len(opt.coco_json) > 0 then
print('reading from ' .. opt.coco_json)
-- read in filenames from the coco-style json file
self.coco_annotation = utils.read_json(opt.coco_json)
for k,v in pairs(self.coco_annotation.images) do
local fullpath = path.join(opt.folder_path, v.file_name)
table.insert(self.files, fullpath)
table.insert(self.ids, v.id)
end
else
-- read in all the filenames from the folder
print('listing all images in directory ' .. opt.folder_path)
local function isImage(f)
local supportedExt = {'.jpg','.JPG','.jpeg','.JPEG','.png','.PNG','.ppm','.PPM'}
for _,ext in pairs(supportedExt) do
local _, end_idx = f:find(ext)
if end_idx and end_idx == f:len() then
return true
end
end
return false
end
local n = 1
for file in paths.files(opt.folder_path, isImage) do
local fullpath = path.join(opt.folder_path, file)
table.insert(self.files, fullpath)
table.insert(self.ids, tostring(n)) -- just order them sequentially
n=n+1
end
end
self.N = #self.files
print('DataLoaderRaw found ' .. self.N .. ' images')
self.iterator = 1
end
The original code would output the the picture and the captions into an .hmtl file randomly. So, picture one would be adjacent to picture 10 would be adjacent to picture 4 would be adjacent to picture 38 (for example).
I can't have it do that, so I edited it:
function DataLoaderRaw:__init(opt)
local coco_json = utils.getopt(opt, 'coco_json', '')
-- load the json file which contains additional information about the dataset
print('DataLoaderRaw loading images from folder: ', opt.folder_path)
self.files = {}
self.ids = {}
if string.len(opt.coco_json) > 0 then
print('reading from ' .. opt.coco_json)
-- read in filenames from the coco-style json file
self.coco_annotation = utils.read_json(opt.coco_json)
for k,v in pairs(self.coco_annotation.images) do
local fullpath = path.join(opt.folder_path, v.file_name)
table.insert(self.files, fullpath)
table.insert(self.ids, v.id)
end
else
-- read in all the filenames from the folder
print('listing all images in directory ' .. opt.folder_path)
local function isImage(f)
local supportedExt = {'.jpg','.JPG','.jpeg','.JPEG','.png','.PNG','.ppm','.PPM'}
for _,ext in pairs(supportedExt) do
local _, end_idx = f:find(ext)
if end_idx and end_idx == f:len() then
return true
end
end
return false
end
local n = 1
local m = 0
local counter = 1
while counter <= #paths.dir(opt.folder_path) - 2 do -- two directories "." and ".." returned by dir that are not images
local file_added = false
for file in paths.files(opt.folder_path, isImage) do
if tonumber(string.sub(file, 7, 10)) == n then -- insert files into self.files in order
if tonumber(string.sub(file, 12, 12)) == m then
local fullpath = path.join(opt.folder_path, file)
table.insert(self.files, fullpath)
table.insert(self.ids, tostring(n)) -- just order them sequentially
m=m+1
counter = counter + 1
file_added = true
break
end
end
end
if file_added == false then
n = n + 1
m = 0
end
end
print(self.files)
end
self.N = #self.files
print('DataLoaderRaw found ' .. self.N .. ' images')
self.iterator = 1
end
The code I wrote is supposed to change that and make it so that picture 1,2,3,4,5...n are all adjacent to each other.
However, I am getting stuck in the while loop.. its looping forever. I really don't know why - this is my first time coding in lua. Hopefully.. a more trained expert would know?
Thank you.

Lua: Check if a table can be looped through via ipairs & ipairs starting at 0

I have a nice little Lua table parser which prints out pretty looking lua code and I love it...it works beautifully. There is a slight snag...if I go to print a table or array that has any integer keys it loops through it using pairs (which doesn't mess the code up ironically), but I would rather it use ipairs if possible. So I want to know is it possible to check a table (without physically looking at it) if it can use ipairs to loop through it first else use pairs. Then is there a way to start looping at 0 instead of Lua's default 1?
Lua Table Parser (Base code found on google, changed it to make it print more array friendly)...
function TableParser(name, object, tabs)
local function serializeKeyForTable(k)
if type(k)=="number" then
return ""
end
if string.find(k,"[^A-z_-]") then
return k
end
return k
end
local function serializeKey(k)
if type(k)=="number" then
if k == 0 then
return "\t[" .. k .."] = "
else
return "\t"
end
end
if string.find(k,"[^A-z_-]") then
return "\t" .. k .. " = "
end
return "\t" .. k .. " = "
end
if not tabs then tabs = "" end
local function serialize(name, object, tabs) -- = {
local output = tabs .. (name ~= "" and name .. " = " or "") .. "{" .. "\n"
for k,v in pairs(object) do
if type(v) == "number" then
output = output .. tabs .. serializeKey(k) .. v
elseif type(v) == "string" then
output = output .. tabs .. serializeKey(k) .. string.format("%q",v)
elseif type(v) == "table" then
output = output .. serialize(serializeKeyForTable(k), v, tabs.."\t")
elseif type(v) == "boolean" then
output = output .. tabs .. serializeKey(k) .. tostring(v)
else
output = output .. tabs .. serializeKey(k) .. "\"" .. tostring(v) .. "\""
end
if next(object,k) then
output = output .. ",\n"
end
end
return output .. "\n" .. tabs .. "}"
end
return serialize(name, object, tabs)
end
So I want to know is it possible to check a table (without physically looking at it) if it can use ipairs to loop through it first else use pairs.
Don't check, just do! Use ipairs first and keep track of the largest key that the ipairs iterator returned. Then use pairs to iterate again and ignore all integer keys between 1 and that largest key from ipairs.
If you really want to check whether ipairs will do something, then look at index 1 in the table (rawget( object, 1 ) ~= nil). Checking whether ipairs will cover all elements in the table is not possible without iterating the table.
Then is there a way to start looping at 0 instead of Lua's default 1?
ipairs(t) returns three values: an iterator function, the table t as the state variable, and an initial index value 0. If you use -1 as initial index value, ipairs will start the iteration at 0 (the iterator function always increments by one before using the index value):
t = { 1, 2, 3, [ 0 ] = 0 }
for i,v in ipairs( t ), t, -1 do -- only use first value returned by ipairs
print( i, v )
end
However, be aware that Lua 5.2 has added support for a new metamethod __ipairs which allows you to return a custom iterator triplet to use for ipairs iteration, and the iterator function returned in this case might need different state and initial index values.
Edit:
To incorporate the suggestions into your code insert before the for k,v in pairs(object) do-loop:
local largest = 0
for k,v in ipairs(object) do
largest = k
local t = type(v)
if t == "table" then
output = output .. tabs .. "\t" .. serialize( "", v, tabs.."\t" )
elseif t == "string" then
output = output .. tabs .. "\t" .. string.format("%q", v)
else
output = output .. tabs .. "\t" .. tostring(v)
end
output = output .. ",\n"
end
and inside the loop add an additional if statement to check for array keys:
for k,v in pairs(object) do
if type(k) ~= "number" or k < 1 or k > largest or math.floor(k) ~= k then
-- if type(v) == "number" then
-- ...
end
end
If you apply this modified TableParser function to the following table:
local t = {
1, 2, 3,
value = "x",
tab = {
"a", "b", field = "y"
}
}
print( TableParser( "", t ) )
the output is:
{
1,
2,
3,
tab = {
"a",
"b",
field = "y"
},
value = "x"
}
But doing table serialization properly is tricky. E.g. your implementation doesn't handle cycles or tables as keys. See the Lua Wiki for some implementations.
You can always iterate a table both with pairs and ipairs, whether it makes sense or not.
ipairs iterates over the sequence present in the array (which means sequential integer keys starting with 1, up to the first missing value), unless overridden with metamethod __ipairs (5.2).
pairs iterates over all key-value pairs with next (thus in an unspecified order), unless overridden with metamethod __pairs (5.2).
Which means that ipairs will generally not enumerate any key-value-pair pairs won't show.
And there is no way to verify whether ipairs will enumerate all keys pairs will enumerate, but enumerating everything and testing manually.
BTW: You can make your own iterator which first iterates over the sequence, and then over everything else:
function my_iter(t)
local k, cap
return function()
local v
if k == nil then k, cap = 0 end
if not cap then
k = k + 1
v = t[k]
if v ~= nil then return k, v end
cap, k = k
end
repeat k, v = next(k)
until type(k) ~= "number" or 0 < k and k < cap and math.ceil(k) == k
return k, v
end
end
Though probably better just sort the keys for pretty-printing:
function sorted_iter(t)
local keys, index = {}, 0
for k in next, t do
keys[#keys + 1] = k
end
table.sort(keys)
return function()
index = index + 1
local k = keys[index]
return k, t[k]
end
end

Lua table.concat

Is there a way to use the arg 2 value of table.concat to represent the current table index?
eg:
t = {}
t[1] = "a"
t[2] = "b"
t[3] = "c"
X = table.concat(t,"\n")
desired output of table concat (X):
"1 a\n2 b\n3 c\n"
Simple answer : no.
table.concat is something really basic, and really fast.
So you should do it in a loop anyhow.
If you want to avoid excessive string concatenation you can do:
function concatIndexed(tab,template)
template = template or '%d %s\n'
local tt = {}
for k,v in ipairs(tab) do
tt[#tt+1]=template:format(k,v)
end
return table.concat(tt)
end
X = concatIndexed(t) -- and optionally specify a certain per item format
Y = concatIndexed(t,'custom format %3d %s\n')
I don't think so: how would you tell it that the separator between keys and values is supposed to be a space, for example?
You can write a general mapping function to do what you'd like:
function map2(t, func)
local out = {}
for k, v in pairs(t) do
out[k] = func(k, v)
end
return out
end
function joinbyspace(k, v)
return k .. ' ' .. v
end
X = table.concat(map2(t, joinbyspace), "\n")
No. But there is a work around:
local n = 0
local function next_line_no()
n = n + 1
return n..' '
end
X = table.concat(t,'\0'):gsub('%f[%Z]',next_line_no):gsub('%z','\n')
function Util_Concat(tab, seperator)
if seperator == nil then return table.concat(tab) end
local buffer = {}
for i, v in ipairs(tab) do
buffer[#buffer + 1] = v
if i < #tab then
buffer[#buffer + 1] = seperator
end
end
return table.concat(buffer)
end
usage tab is where the table input is and seperator be both nil or string (if it nil it act like ordinary table.concat)
print(Util_Concat({"Hello", "World"}, "_"))
--Prints
--Hello_world

Resources