This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Beatsleigher's profile picture

Reading data from file, splitting lines by whitespace

Started by Beatsleigher, 10 August 2017 - 07:54 PM
Beatsleigher #1
Posted 10 August 2017 - 09:54 PM
Hey there,

I've got a computer in my house which controls access to the machine room (machines and ME system) via a teleporter.
We're a couple friends on the server, so for gits and shiggles I created a login system for the access terminal.

This works fine for the first user in the file; all the other users will not work this way.

The file is structured as follows:


user0	password
user1	password
...

I wrote this piece of code and it only just came to me that it wasn't working correctly:

-- [[ Functions ]] --
local function getUsers()
	handle = fs.open(userConf, "r")
	if handle == nil then
		return userTable, 0
	else
		local rawData = handle.readAll()
		print(rawData)
		for s in string.gmatch(rawData, ".*$") do
			-- do stuff with line
			userSplit = {}
			for word in s:gmatch("%w+") do
				table.insert(userSplit, word)
				--print(word)
				--sleep(2)
			end
			table.insert(userTable, userSplit)
		end
		return userTable, #userTable
	end
end

The result I'm looking for and also expecting in the other functions, is a table looking something like this, which the above code does not produce.


local users = {
  { "user0", "password" },
  { "user1", "password" },
  ...
}

Essentially, I'm trying to do this (jotted down C# code), if it makes it clearer…

Dictionary<string, string> GetUsers() {
	    var lines = File.readAllLines("/path/to/file.conf");
	    var returnVal = new Dictionary<string, string>();
	    foreach (var line in lines) {
		    var split = Regex.Split(line, @"\s{1,}");
		    returnVal.Add(split[0], split[1]);
	    }
	    return returnVal;
    }

Thanks in advance for any and all help; sorry if I didn't make myself clear enough!
SquidDev #2
Posted 10 August 2017 - 10:20 PM
I'd probably do something like this:


local handle = fs.open(userConf, "r")
if not handle then return userTable, 0 end

for line in handle.readLine do
    local user, password = line:match("^(%S+)%s+(.*)$")
    if not user then
        print("Malformed line: " .. user)
    else
         userTable[user] = password
         --# Or do table.insert(userTable, { user, password }) - the above line generates a "dictionary" like the C# code.
    end
end
handle.close()

The main trick here is "iterating" using handle.readLine. This is effectively equivalent to:

while true do
    local line = handle.readLine()
    if not line then break end
end
Beatsleigher #3
Posted 10 August 2017 - 10:37 PM
@SquidDev No need to put interating in quotes :P/>
I work as a professional software developer, using C# :)/>

Anyways, I've sorted it:

local function getUsers()
  handle = io.open(userConf, "r")
  if handle == nil then
	  return userTable, 0
  else
	   
    for line in handle:lines() do
	  lineTable = {}
	  for word in line:gmatch("%S+") do
	    --print(word)
	    --sleep(0.5)
	    table.insert(lineTable, word)
	  end
	  table.insert(userTable, lineTable)
    end
    --[[for i = 1, #userTable do
	  print("Level " .. i .. " of userTable:")
	  for j = 1, #userTable[i] do
	    print("  Level " .. i .. "." .. j .. ":")
	    print("    " .. userTable[i][j])
	  end
	  sleep(1)
    end
    sleep(5)]]--
    return userTable, #userTable
  end
end

Minor brainfarts, I'm still too used to C#, hahaha