Delete the last line of a variable

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.

can anybody help me?

I don’t understand this post.  Can you elaborate step by step what you’re doing and refer to the SSK feature(s) you’re using?

Also, define what “Ctrl Z” means to you.  There is no uniform meaning for that key input combination.

Note: As part of your description you could explain your steps as:

  1. I have this ABCDEFG stored in a variable (or stored as a field in a table; or stored in file, or whatever the case is)

  2. I press CTRL+Z

  3. I want the string to now be ???  

Be very deliberate, clear, concise, and precise in your description and again, reference the specific SSK feature(s) you’re using.

Hi,

Something like this should work.

function trimNewline(str) return(string.gsub(str, '\n$', '')) end

-dev

Ctrl + Z, maybe means undo?

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:
 

Answer1 /n Answer 2 /n Answer 3 /n Answer 4 /n Answer 5 /n Answer 6 /n .... Answer 444 /n Answer 445 /n Answer 446 /n Answer 447 /n

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:
 

Answer1 /n Answer 2 /n Answer 3 /n Answer 4 /n Answer 5 /n Answer 6 /n .... Answer 444 /n Answer 445 /n Answer 446 /n

And if it squeezes twice, I will have the following value inside my CSV file
 

Answer1 /n Answer 2 /n Answer 3 /n Answer 4 /n Answer 5 /n Answer 6 /n .... Answer 444 /n Answer 445 /n

And if you press again …
 

Answer1 /n Answer 2 /n Answer 3 /n Answer 4 /n Answer 5 /n Answer 6 /n .... Answer 444 /n

This inside the corona is read inside a common variable, which was the example of the beginning of the topic.
The stored variable is as follows:
 

output = Response 1 / n Response 2 / n Response 3 / n Response 4 / n Response 5 / n ...

Then I would like to know how I can remove only the last response from the variable.

*NOTE: Each answer is not just a value. in an answer I have several values ​​that are organized into different columns in excel. That is, I have this:

Answer 1 = "Something"; "Another thing" ; "another thing" ; "another thing" ; "another thing".

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

If you are using new-line characters to separate answers I would suggest you not do that. 

I would only use new-line to separate groups of answers.

MY GOD IS EXACTLY THIS FIRST CODE OF YOURS!

Except that I have a problem, your string for example was like this:

local date = “Bob / Bill / Sue / Eddie”

Except that my string ALWAYS ends with a / n at the end, so when I run your code, the following happens:

local data = “Bob / nBill / nSue / nEddien /”

BEFORE: Bob /n Bill /n Sue /n Eddie /n
AFTER: Bob /n Bill /n Sue /n Eddie

Do you have any solutions for this not to happen? That is, it has to ignore the last 2 characters

_Note, the only difference from your code to mine was that you thought you had only “/” and it actually is “/n” _

Hi,

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

-dev

  1. @dev is right.  That is not a newline

  2. 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.

  3. 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

Could you please explain in some other way why you do not use “\ n”? In case the user enters \ n and the program ends up getting confused?

Because I’m currently using the '; “to separate columns and the” \ n "to break lines …

Hi,

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

Usage :

--############################################################################# --# CSVState Module usage --############################################################################# local CSVState = require("CSVState") --############################################################################# --# 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" --############################################################################# --# Tests --############################################################################# print('----------------------------') output = CSVState.undo(output) print(output) print('----------------------------') output = CSVState.undo(output) print(output) print('----------------------------') output = CSVState.redo(output) print(output) print('----------------------------') output = CSVState.redo(output) print(output)

Result :

---------------------------- NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y LUCAS;912;4;-20.2821881;-40.3207234 TADEU;4;45;-20.2893585;-40.3987237 ---------------------------- NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y LUCAS;912;4;-20.2821881;-40.3207234 ---------------------------- NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y LUCAS;912;4;-20.2821881;-40.3207234 TADEU;4;45;-20.2893585;-40.3987237 ---------------------------- NAME;VALUE;TOTAL;COORDINATE X;CORDINATE Y LUCAS;912;4;-20.2821881;-40.3207234 TADEU;4;45;-20.2893585;-40.3987237 PAULO;9;2;-20.1814675;-40.41288597

EDIT: Updated for ‘\n’ usage.

-dev

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?

Hi,

I’ll take a look. Gimme a few.

-dev

Hi,

Try this update to the module:

--############################################################################# --# 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

Hopefully that should do what you want. 

-dev

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  ;) 

Hi,

Thanks! Glad to help.  :wink:

-dev

I don’t understand this post.  Can you elaborate step by step what you’re doing and refer to the SSK feature(s) you’re using?

Also, define what “Ctrl Z” means to you.  There is no uniform meaning for that key input combination.

Note: As part of your description you could explain your steps as:

  1. I have this ABCDEFG stored in a variable (or stored as a field in a table; or stored in file, or whatever the case is)

  2. I press CTRL+Z

  3. I want the string to now be ???  

Be very deliberate, clear, concise, and precise in your description and again, reference the specific SSK feature(s) you’re using.

Hi,

Something like this should work.

function trimNewline(str) return(string.gsub(str, '\n$', '')) end

-dev