Hello, I use SSK to export a file (.CSV) to a device folder, and I have a variable that holds all the values to perform the export. An example of the variable is this:
output = "NAME ; VALUE ; TOTAL ; COORDINATE X ; CORDINATE Y /n LUCAS ; 912 ; 4 ; -20.2821881 ; -40.3207234 /n TADEU ; 4 ; 45 ; -20.2893585 ; -40.3987237 /n PAULO ; 9 ; 2 ; -20.1814675;-40.41288597 /n
I would like to implement a “ctrl Z” function in my application, and this requires removing the last line of this variable (the last line would be the last /n … /n ).
I thought about using a mixture of “output:sub” with “output:find” but I really could not succeed.
Reading again really was confusing.
Well, I’ll explain the whole context.
(There’s no way you can type ABCDEFG, that’s not how it works.)
I ask the user to fill out a form, every time the user has just completed this form I update a .CSV file with a new data entry. (This .CSV file is a huge table to open in EXCEL)
Every time the user has just completed the form and hit the “forward” button I have a new line in my .CSV file and I can identify this last line by the penultimate value of line break (/n).
Think of the following, each “answer” are several values in several columns, and in my CSV file I have the following:
When the user presses “Ctrl + Z” it is because he entered wrong data in the last response, so I have to delete from my .CSV file (ie, I have to delete from my variable) the last response entered.
Only he can press this repeatedly, following the example above, the file would look like this after the user hit the undo button:
Honestly, I’m still confused. Thanks for being detailed, but that is simply too much information and I suspect a lot of it is not related to the question.
It sounds like you simply want to remove the last ‘answer’ from a string stored in a variable where the string may contain multiple answers separated by a known and fixed separator symbol.
local function removeLastAnswer( str, sep ) local lastSep = str:match('^.\*()' .. sep) if( lastSep == nil) then return "" end return(str:sub(1,lastSep-1)) end local data = "Bob;Bill;Sue;Eddie" print( "BEFORE", data ) data = removeLastAnswer(data,";") print( "AFTER", data ) local data = "Bob" print( "BEFORE", data ) data = removeLastAnswer(data,";") print( "AFTER", data ) local data = "Bob/Bill/Sue/Eddie" print( "BEFORE", data ) data = removeLastAnswer(data,"%/") print( "AFTER", data )
If you want to do this to a line in a file, you need to read the entire file into memory, locate the last line, and do the above to that line.
So, if that is the case, you can use the above code + some SSK:
local function removeLastAnswerInFile( fileName, sep, base ) local data = io.readFileTable( fileName, base ) data[#data] = removeLastAnswer( data[#data] ,"sep") for i = 1, #data do local line = data[i] if( string.len( line ) \> 0 ) then if( i == 1) then io.writeFile(line .. "\n", fileName, base ) else io.appendFile(line.. "\n", fileName, base ) end end end end
The ‘/n’ is actually not a “newline” character sequence (that would be “\n”).
Here is my less elegant solution compared to @roaminggamer:
--############################################################################# --# Output data --############################################################################# local output = "NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y/nLUCAS;912;4;-20.2821881;-40.3207234/nTADEU;4;45;-20.2893585;-40.3987237/nPAULO;9;2;-20.1814675;-40.41288597/n" --############################################################################# --# Split utility --############################################################################# local function split(inputstr) local t={} ; i=1 for str in string.gmatch(inputstr, "([^/n]+)") do t[i] = str i = i + 1 end return t end --############################################################################# --# Remove last line --############################################################################# local function removeLastLine(output) local output = split(output) if #output \> 1 then -- protect CSV headers table.remove(output) return table.concat(output, '/n') .. '/n' else return 'no more lines to remove' end end --############################################################################# --# Tests --############################################################################# print('--------------------------------') output = removeLastLine(output) print(output) print('--------------------------------') output = removeLastLine(output) print(output) print('--------------------------------') output = removeLastLine(output) print(output) print('--------------------------------') output = removeLastLine(output) print(output)
Results:
-------------------------------- NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y/nLUCAS;912;4;-20.2821881;-40.3207234/nTADEU;4;45;-20.2893585;-40.3987237/n -------------------------------- NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y/nLUCAS;912;4;-20.2821881;-40.3207234/n -------------------------------- NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y/n -------------------------------- no more lines to remove
Again, I would NOT use the same character to cap a line (at the end) as i use to separate elements of a line. This will just cause you trouble.
Instead I would use a special or unused character as the tween-answer separator like any of these: ~ or ^ or ; or & or ‘\1’ or or ‘\2’ … et.c
If your user is typing this into a spredsheet, have them save the CSV using the traditional comma as the separator and if they need a comma in the bit they type have them use ~. Then you can late convert all ~ to commas in the end usage.
First I wanted to apologize to everyone on this topic, I did not really mean /nn and yes \n I totally confused and was ignorant in not realizing rs
I would also like to thank in particular @roaminggamer and @Develephant you really are exceptional, thanks for taking the time to help me, this Corona team is SENSATIONAL, thank you all.
@Develephant’s code worked exactly the way I wanted, showing excellent result, for my specific case it did very well. If someone needs something more generalized and ended up falling from parachute here, I also recommend the @roaminggamer code.
More below I will be leaving the result !!
local function split(inputstr) local t={} ; i=1 for str in string.gmatch(inputstr, "([^\n]+)") do t[i] = str i = i + 1 end return t end --############################################################################# --# Remove last line --############################################################################# local function removeLastLine(output) local output = split(output) if #output \> 1 then -- protect CSV headers table.remove(output) return table.concat(output, '\n') .. '\n' else return 'no more lines to remove' end end output = removeLastLine(output)
RESULT:
15:30:43.380 -------------------------------- 15:30:43.380 NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y 15:30:43.380 LUCAS;912;4;-20.2821881;-40.3207234 15:30:43.380 TADEU;4;45;-20.2893585;-40.3987237 15:30:43.380 15:30:43.380 -------------------------------- 15:30:43.380 NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y 15:30:43.380 LUCAS;912;4;-20.2821881;-40.3207234 15:30:43.380 15:30:43.380 -------------------------------- 15:30:43.380 NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y 15:30:43.380 15:30:43.380 -------------------------------- 15:30:43.380 no more lines to remove
Because it’s Saturday and I’m bored ;) , here is another solution that may be interesting in the event the user removes a line (or more) by mistake. It is in a module format that facilitates undo and redo functionality.
Module:
--############################################################################# --# CSVState module --############################################################################# local \_M = { undos = {} } --############################################################################# --# Split utility --############################################################################# local function split(inputstr) local t={} ; i=1 for str in string.gmatch(inputstr, "([^\n]+)") do t[i] = str i = i + 1 end return t end --############################################################################# --# Undo --############################################################################# function \_M.undo(data) local lines = split(data) if #lines \> 1 then -- dont remove headers table.insert(\_M.undos, 1, table.remove(lines)) return table.concat(lines, '\n') .. '\n' else return data end end --############################################################################# --# Redo --############################################################################# function \_M.redo(data) if #\_M.undos \> 0 then return data .. table.remove(\_M.undos, 1, -1) .. '\n' else return data end end return \_M
My God … ! It took me a while to respond because I was enjoying this code :o :o
Thank you so much, this beyond helping me too much made me understand a part of the module that I did not understand.
Now, just a detail that I have no idea how to fix (I tried here kk) The code you sent (with module) is bugging when you have no more content to “undo”, it is locking the console, this is as follows error message:
17:16:34.492 C:\Users\pablo\OneDrive\Área de Trabalho\..\CSVState.lua:13: bad argument #1 to 'gmatch' (string expected, got nil) 17:16:34.492 stack traceback: 17:16:34.492 [C]: in function 'gmatch' 17:16:34.492 C:\Users\pablo\OneDrive\Área de Trabalho\..\CSVState.lua:13: in function 'split' 17:16:34.492 C:\Users\pablo\OneDrive\Área de Trabalho\..\CSVState.lua:24: in function 'undo'
And when you re-do more than necessary content the output variable becomes null (as if it had output = nil) do you know why this is happening?
--############################################################################# --# CSVState module (CSVState.lua) --############################################################################# local \_M = { undos = {} } --############################################################################# --# Split utility --############################################################################# local function split(inputstr) local t={} ; i=1 for str in string.gmatch(inputstr, "([^\n]+)") do t[i] = str i = i + 1 end return t end --############################################################################# --# Undo --############################################################################# function \_M.undo(data) local lines = split(data) if #lines \> 1 then -- protect CSV headers table.insert(\_M.undos, 1, table.remove(lines)) return table.concat(lines, '\n') .. '\n' else return data end end --############################################################################# --# Redo --############################################################################# function \_M.redo(data) if #\_M.undos \> 0 then return data .. table.remove(\_M.undos, 1, -1) .. '\n' else return data end end return \_M
I sincerely miss words to thank you. This is exactly what I needed and this solution you developed and introduced me was VERY VERY VERY GOOD.
Thank you very much, if you had here in Brazil I could talk to you “MANO VOCÊ É MUITO FODA OBRIGADO” but in English I do not know how this is, so feel that I praised you enough and I am VERY thankful hahahahahah :D :D ;)