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

Need help with patterns

Started by Dragon53535, 31 March 2015 - 05:22 PM
Dragon53535 #1
Posted 31 March 2015 - 07:22 PM
I'm currently working on a system for me to better understand the chemistry homework that I'm struggling with, and to do so, I need to be able to break the chemical formulas up into parts that allows me to work with them.

Example:

Lets say I have the chemical formula

CuSO4 + KCl = CuCl2 + K2SO4
I want to be able to split the formula into different parts based on their elements. I'll be inserting them into a table myself, but I'll use the end result of the table to show you what I want.


reactant1 = {Cu = 1, S = 1, O = 4}
reactant2 = {K = 1, Cl = 1}
product1 = {Cu = 1, Cl = 2}
product2 = {K = 2, S = 1, O = 4}

If you know chemistry, you can tell that this equation isn't balanced, and even though it would be easy for me to do, I'd like to be able to program it as well, (I can probably do that on my own, just need the splitting)


Now for my code currently,


local function findChem(str)
  for word in string.gmatch(str,'%u%l%u*%d*') do
    print(word)
  end
end
findChem("CuSO4")

Using this it WILL print out CuSO4, however that's on one line, how do I get it so that Cu is on one line S on another O on the next, and 4 on the last??
KingofGamesYami #2
Posted 31 March 2015 - 07:30 PM

function findChem( str )
  for chem, num in str:gmatch( "(%u%l?)(%d*)" ) do
    print( chem .. ": " .. (num ~= "" and num or 1) )
  end
end
findChem( "CuSO4" )

Like this?

Edit: I haven't taken chem, can there be more than one lowercase letter? If so, change the ? to a *.
Edited on 31 March 2015 - 05:31 PM
Dragon53535 #3
Posted 31 March 2015 - 07:34 PM
Okay that's great thank you for that, could you explain it to me however? and how would I edit it to find + or =? Just find them, I can handle them

Also, no, only 1 lowercase
Edited on 31 March 2015 - 05:36 PM
KingofGamesYami #4
Posted 31 March 2015 - 07:38 PM
Alright, here goes.


"(%u%l?)(%d*)"

First off, parentheses () return what is between them, allowing us to get multiple returns (if no parentheses are present, entire result is returned).

%u matches a single uppercase letter
%l? matches 0 or 1 lowercase letters If changed to *, it would match 0 or more lowercase letters.
%d* matches 0 or more numbers (0-9). If it doesn't match anything, an empty string ("") is returned.

Edit: I'll do equations later, I have school…
Edited on 31 March 2015 - 05:40 PM
Dragon53535 #5
Posted 31 March 2015 - 07:44 PM
Gotcha, thanks for your help anyways Yami :D/>

Okay think I actually got it on my own with Yami's help here. It took me a minute, but I realized it grabbed from the string what it found, and when I kept trying stuff on the right side of the pattern, it would grab from the rest of the string, HOWEVER, if I added it to the left side of the pattern, it would return an empty string UNTIL it found what it was looking for.


function findChem( str )
  for nxt,co,chem,num in str:gmatch( "(%W*)(%d*)(%u%l?)(%d*)" ) do
    print( nxt )
    print( co )
    print( chem )
    print( num~="" and num or 1 )
  end
end
nxt being + or =, and co being a coefficient. Now I can work on getting it to balance itself, or check if it's balanced, and then do my equations :D/>
Edited on 31 March 2015 - 06:06 PM
KingofGamesYami #6
Posted 31 March 2015 - 07:58 PM

local function getEquation( str )
	local left = {}
	local right = {}
	local has_passed
	for a, b in str:gmatch( "([^%+=]+)([%+=]?)" ) do
		if has_passed then
			right[ #right + 1 ] = a
		else
			left[ #left + 1 ] = a
		end
		if b == "=" then
			has_passed = true
		end
	end
	return left, right
end

local left, right = getEquation( "CuSO4 + KCl = CuCl2 + K2SO4" )

:)/>
Creator #7
Posted 31 March 2015 - 08:09 PM
Firstly make something like this:


function getSides(sInput)
local sides = {}
for token in string.gmatch(sInput,"[^=]+") do
  sides[#sides+1] = token
end
return sides[1], sides[2]
end
function getMolecules(sInput)
local buffer = {}
for token in string.gmatch(sInput,"[^%s]+") do
  buffer[#buffer+1] = token
end
return buffer
end

local left, right = getSides(equation)
left = getMolecules(left)
right = getMolecules(right)

It will give you the different molecules divided by sides.
Dragon53535 #8
Posted 31 March 2015 - 08:10 PM
Well that works well, probably be easier to use yours and break down it's strings using the original setup, but I think I might be able to make mine work :P/>

Edit: typed before seeing Creator's i'll read that now. Also, yami I think I understand yours, it operates under the assumption that there's always two on one side of the equation though. Or not, tested and it doesn't, hmmmmmmmmmm

Okay, so Yami's code, let's see if I understand it correctly. It searches for any characters that are NOT + or =, with 1 or more occurrences and returns that as a, and then it searches after that FOR + or = with 0 or 1 occurrences, and then returns that as b. Quite clever, hmm.


Edit3ish: I could not for the life of me get Creator's code to work. Even after pcalling his getMolecule function. Attempt to use table value or something.
Edited on 31 March 2015 - 06:23 PM
KingofGamesYami #9
Posted 31 March 2015 - 08:14 PM
It does assume you only have one equals sign. It might screw up if you add more…