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

Splitting String With \n Into Table of Strings

Started by augustas656, 23 May 2014 - 08:41 PM
augustas656 #1
Posted 23 May 2014 - 10:41 PM
How could create perhaps like a for loop, or any type of code in a function that takes in a string and finds \n, removes them and splits all the strings in-between, so a string such as 123\nabc\n456 would be split into a table of {123, abc, 456}. I know how I could head with this, using string.match, string.sub, or perhaps something like this but I'm still somewhat not sure.

I need this for my API function that firstly if a parameters allows splitting at \n spots, it will split then split the string whrereit finds \n, and after that, it splits the string to the given area, if no area is given it will use screen's width as default. So a string 105 characters would be split into 51, 51 and 3 characters.

Regards
Augustas
Lignum #2
Posted 23 May 2014 - 10:49 PM
You'd do something like this:

local lines = {}
local text = "Hello\nWorld!"

--# [^\r?\n\r?] means "anything that isn't a new line, optionally prefixed or suffixed with a carriage return"
for match in text:gmatch("[^\\r?\\n\\r?]") do
	 lines[#lines + 1] = match
end


See theoriginalbit's answer.
Edited on 24 May 2014 - 07:23 AM
augustas656 #3
Posted 23 May 2014 - 11:01 PM
Can you please explain what do yuo mean by optionally prefixed or suffixed with a carriage return?

Regards
Augustas

I'm sorry, your code splits my string into char after char, so like hello world is split into h, e, l, l, o, , w, o, r, l, d?
Edited on 23 May 2014 - 08:58 PM
CometWolf #4
Posted 23 May 2014 - 11:07 PM
He forgot to add a + sign to his custom character class

text:gmatch("[^\\r?\\n\\r?]+")
Although i can't say wether it will work or not still, since i believe +-? and the like don't work the same way within custom classes. Something like

text:gmatch("(.+)\n?")
would probably be enough

Personally i use string.find for this, so idk, it mgiht work, it might not. Give it a try i suppose.
Edited on 23 May 2014 - 09:08 PM
augustas656 #5
Posted 23 May 2014 - 11:19 PM
How do you (personally CometWolf) use string.find? I personally done something while there's an \n array[#array + 1] is equal to the string before \n, then string is string removed the first part including the \n. But the problem with that is it doesn't include the last remaining part of the string after the last \n.

Regards
Augustas
augustas656 #6
Posted 23 May 2014 - 11:27 PM
Okay I got it to work with the +, thanks, but can someone explain what Lignum meant by optionally prefixed or suffixed with a carriage return?

Regards
Augustas
CometWolf #7
Posted 23 May 2014 - 11:41 PM
"\r" is the character for carriage return, and the question mark means they are an optional match, ie. not needed. However i don't believe question marks work that way within custom classes([]).
For the record, here's the function i use

string.lineFormat = function(text,lineLength,center)
  local tLines = {}
  while #text > 0 do  --splits text into a table containing each line
    local line = text:sub(1,lineLength)
    local newLine = string.find(line.."","\n") --check for new line character
    if newLine then
	  line = line:sub(1,newLine-1)
	  text = text:sub(#line+2,#text)
    elseif #line == lineLength then
	  local endSpace = line:find"%s$" or line:find"%s%S-$" or lineLength
	  line = line:sub(1,endSpace)
	  text = text:sub(#line+1)
    else
	  text = ""
    end
    if center then
	  line = string.rep(" ",math.max(math.floor((lineLength-#line)/2),0))..line
	  line = line..string.rep(" ",math.max(lineLength-#line,0))
    end
    tLines[#tLines+1] = line
  end
  return tLines
end
theoriginalbit #8
Posted 24 May 2014 - 01:23 AM
You'd do something like this:

local lines = {}
local text = "Hello\nWorld!"

--# [^\r?\n\r?] means "anything that isn't a new line, optionally prefixed or suffixed with a carriage return"
for match in text:gmatch("[^\\r?\\n\\r?]") do
	 lines[#lines + 1] = match
end
did you actually test your code before posting it to 'help'? I have a feeling you didn't!

adding a table.concat(lines, ' ') at the end of your script will show you why I think this… here's the output

H e l l o
 W o r l d !
notice how the new line is still there, that is because you've escaped the backslash by doing \\ … newline is \n or \r and the combinations of those two, so your loop should look like

for match in text:gmatch("[^\r?\n\r?]") do
  lines[#lines + 1] = match
end
however that still 'causes one little problem, take a look at the output from the table.concat

H e l l o W o r l d !
now this output is because your pattern has it ignore new lines, however it only does that one character… CometWolf's response holds the answer, your loop should look like this

for match in text:gmatch("[^\r?\n\r?]+") do
  lines[#lines + 1] = match
end
now if you take a look at the output from table.concat you'll notice it has worked as intended

Hello World!


I don't like having to correct the 'pros' but sadly its getting to the point where 1) people either don't know what they're talking about when trying to help, or 2) they don't test their code before posting, a crucial step in making sure you provide accurate help, not just more problems and headaches for the OP.
Edited on 23 May 2014 - 11:23 PM
Lignum #9
Posted 24 May 2014 - 09:23 AM
did you actually test your code before posting it to 'help'? I have a feeling you didn't!
No, I didn't. This seemed simple enough to me but it was a little late at night… a bit very late.
Anyway, sorry about that. Confidence is evil.