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

Split a string in two variables

Started by Ermans, 10 February 2013 - 11:37 AM
Ermans #1
Posted 10 February 2013 - 12:37 PM
Title: Split a string in two variables


Hello, this is my question:
If I have a string with this formatting :

message="/add a_number"

How I can capture the code from " / " to space and the code after the space and assign two variable?

Thanks for help and sorry if the my english is bad, because I not speak (and I not write) english very well.
Kingdaro #2
Posted 10 February 2013 - 12:50 PM
You can use gmatch and capture all non-space characters.


local message = "/add a_number"
local words = {}

for word in message:gmatch('%S+') do
  table.insert(words, word)
  print(word)
end

For these purposes, the script prints every word it finds. The output would be this:

/add
a_number
Eric #3
Posted 10 February 2013 - 01:41 PM

local command, args = message:match('/(.-) (.+)')
Kingdaro #4
Posted 10 February 2013 - 01:45 PM

local command, args = message:match('/(.-) (.+)')
Doesn't work well with more than one argument, but it would work if OP only wants one argument allowed.
Doyle3694 #5
Posted 10 February 2013 - 03:33 PM
Also, just to clearify because I think you are new to lua, and they are using :'s. : will enter the table it's called from as the first argument, so message:gmatch('%S+') would be the same as string.gmatch(message,'%S+').

Just a clarification, not really connected to your first question, but I know it bugged me when I didn't know what it ment :P/>
Ermans #6
Posted 10 February 2013 - 10:42 PM
Thanks at all for fast reply.
But if I have this code:

message-size-color
example:

Hello World-5-red

How I split that in 3 variable?
Same Kingdaro's process?
Eric #7
Posted 10 February 2013 - 11:47 PM
local message, size, color = message:match('/(.+)-(.-)-(.-)')
Kingdaro #8
Posted 11 February 2013 - 06:13 AM
local message, size, color = message:match('/(.+)-(.-)-(.-)')
The minus symbol needs to be escaped.

local message, size, color = message:match('/(.+)%-(.-)%-(.-)')
Ermans #9
Posted 11 February 2013 - 06:17 AM
You can use gmatch and capture all non-space characters.


local message = "/add a_number"
local words = {}

for word in message:gmatch('%S+') do
  table.insert(words, word)
  print(word)
end

For these purposes, the script prints every word it finds. The output would be this:

/add
a_number

Thanks, it works!

Now I want split a variable like this:

message-size-color
But the code of Eric don't work :(/>


So I want write a string that contain three variable (string, number, string) , but i think the hyphen isn't good way to do this.
How I can do it fine?
Djerun #10
Posted 11 February 2013 - 10:42 AM
you could use string.find to search for the position of your dividing character, then use string.sub to save the part before it to a variable or table (append the empty string to it (.."") to make sure new memory is allocated for it) then use string.sub to save the part after the divider to the same variable you were reading from again make sure new memory is allocated for it by appending the empty string.
repeat this until your variable holding the message does not contain the divider anymore. it now holds the last part of your message


I wrote a little testprogram for this

local argv = { ... }
local msg = argv[1]
local Table = {}
local index = 1
local divider = "-"
if msg ~= nil then
  local pos = string.find(msg, divider)

  while pos ~= nil do
	Table[index] = string.sub(msg, 1, pos - 1)..""
	index = index + 1
	msg = string.sub(msg, pos + 1)
	pos = string.find(msg, divider)
  end

  Table[index] = msg

  for i = 1, index do
	print(Table[i])
  end

end
and after confirming it working by the program logic logic tested it with
testprog test-1-2-3
testprog test-1-2-3-
testprog -
testprog
the first works just fine
the second creates an empty string in the last table entry
the third creates a table with two empty entries
the fourth does nothing (obviously)
Kingdaro #11
Posted 11 February 2013 - 10:47 AM
Really, guys. Just use gmatch.


local message = "message-size-color"
local words = {}

for word in message:gmatch('[^%-]+') do
  table.insert(words, word)
end

print(words[1]) --> message
print(words[2]) --> size
print(words[3]) --> color

Though eric's method works fine, as long as you only need three arguments, and as long as the dashes are escaped in the match string.

local message, size, color = message:match('(.+)%-(.+)%-(.+)')
Djerun #12
Posted 11 February 2013 - 11:07 AM
gmatch needs knowledge about regular expressions (which every programmer should have because they are really handy) and which extra rules apply to them in lua (at least here) which certainly not everyone starting out with CC has or is willing to learn.

if you solve a problem with regular expressions you should at least link to somewhere someone could learn more about them in case he can learn more about them and doesn't have to ask a new question every time that knowledge could be applied (ofc those who don't want to know it simply wouldn't read it and ask again with the next problem)

and since this is a rather small problem since only one character needs to be detected a more basic solution doesn't hurt (unless CC generates an insane amount of overhead) and also may teach one more about strings (which is even more important that learning about regexpr)
Kingdaro #13
Posted 11 February 2013 - 11:33 AM
OP didn't specifically ask for an easy-to-understand overly-complicated solution, he/she just wanted a valid answer to the problem, and with that in mind, I provided the most efficient solution that would take the least amount of time to type, and probably is most logical.

Also, Lua patterns aren't regular expressions. If you insist the OP should learn more, here's a link about lua patterns.

Reference Manual:
http://www.lua.org/manual/5.1/manual.html#5.4.1

And in lua-users since that's usually easier to understand:
http://lua-users.org/wiki/PatternsTutorial
Ermans #14
Posted 11 February 2013 - 11:34 AM
Thanks at all ;)/>
Now it works!
Djerun #15
Posted 11 February 2013 - 01:03 PM
OP didn't specifically ask for an easy-to-understand overly-complicated solution, he/she just wanted a valid answer to the problem, and with that in mind, I provided the most efficient solution that would take the least amount of time to type, and probably is most logical.
what exactly do you think gmatch does behind the scenes?
Kingdaro #16
Posted 11 February 2013 - 01:27 PM
what exactly do you think gmatch does behind the scenes?
I hate it when people say things like this. It's the same logic as manually maintaining coroutines yourself instead of using the parallel API, because that's what parallel does behind the scenes, but it's there for a reason. Why do in 20 lines what you could do in 3?

Plus, if there's a better solution, fuck all if it's too difficult for you to use. Just learn about it instead of sticking with the same old outdated primitive methods.
ChunLing #17
Posted 12 February 2013 - 11:48 AM
I think that, behind the scenes, gmatch is written in C (or Java, depending on implementation) and is crazy faster than anything equivalent you could write in Lua without using gmatch.

It's well worth knowing how to use it.
Djerun #18
Posted 12 February 2013 - 05:43 PM
I think that, behind the scenes, gmatch is written in C (or Java, depending on implementation) and is crazy faster than anything equivalent you could write in Lua without using gmatch.
that definetly depends on how exactly the lua is sandboxed but it's most likely faster(because it's interpreted and gmatch most likely uses a compiled functionality)
most code for compiled languages is translated to C but it really depends on the compilers quality. just because something is in C it doesn't mean its fast (being compiled over being interpreted most times means compiled is faster though)
It's well worth knowing how to use it.
and I did not doubt that
I hate it when people say things like this. It's the same logic as manually maintaining coroutines yourself instead of using the parallel API, because that's what parallel does behind the scenes, but it's there for a reason. Why do in 20 lines what you could do in 3?

Plus, if there's a better solution, fuck all if it's too difficult for you to use. Just learn about it instead of sticking with the same old outdated primitive methods.

for a, b, c, d in string.gmatch("TUFS", "^(%a)(%u)(%x)(%w)$") do print(d, a, c, b) end
Eric #19
Posted 12 February 2013 - 09:10 PM
CC's gmatch is in bios.lua (for reasons I don't fully understand), and falls back on :find (which is java-side)
ChunLing #20
Posted 13 February 2013 - 12:24 PM
What? Where? Who?
Lyqyd #21
Posted 13 February 2013 - 12:30 PM
It and the re-implementations of pairs, etc. are there so that serialization of the entire state will be easier, and is a precursor to eventual persistence across chunk loads.
ChunLing #22
Posted 13 February 2013 - 12:37 PM
Well, that's quite new then. The time of persistence is almost upon us!