Calculator Issues

Hello! I have been trying to make a calculator but, the issue is it’s all in a string and strings don’t run operators and special characters. So, an example would be this:

"123*428"

And this won’t be calculated so how would a perform the calculations with any string including:

./*=+-%
1 Like

You can’t use a string value. You need to use an int or number value.

Example:

local number1 = 10
local number2 = 5

print(number1 + number2)

Well… I can get the numbers to not be a string, but the operators have to…

you could so something like

local number1 = tonumber("1")
local number2 = tonumber("2")

if operator == "+" then
      print(number1 + number2)
end
--// etc.
2 Likes

This is right. You can try tonumber.

1 Like

try making it so that every input is added to a table

once the equal sign is pressed parse the numbers and print an answer

(e.g.
local table = {5, *, 3}
parse 5 and 3 and read the asterix as to multiply the 2)

(tbh probably not gonna work but its an idea)

1 Like

string.split for the * string. returns a table. or a tuple? idk

1 Like

I’ll try! It might be a while though.

Oh actually, no that wouldn’t work if I had more than one operator.

just add elseif’s
like

if operator == "+" then
      print(number1 + number2)
elseif operator == "-" then
      print(number1 - number2)
-- etc.
end

I mean like if I had:

5*3/2

You can use string.split(Input, Operator). Here’s a small example:

--Define usuable mathematic operations, with the operator and the function the operator should use
local Operations = {
	{
		Name = "+",
		Func = function(A, B)
			return A + B
		end,
	},
	
	{
		Name = "-",
		Func = function(A, B)
			return A - B
		end,
	}
}

local Input = "5+5"

local function Calculate(InputString)
	--Go through the defined operaations till you find one that's used in the input string
	for _, Operation in pairs(Operations) do
		--Check for numbers on the right and left of the operator symbol (aka, "+", "-", etc)
		--string.split converts the string into a table by using the delimiter (in this case, the operation) to "split" the string into pieces.
		local Numbers = string.split(Input, Operation.Name)
		
		--#Numbers == 2: Verifies a match was found
		--tonumber(Numbers[1 - 2]): Verifies the numbers found can be converted to actual numbers
		if #Numbers == 2 and tonumber(Numbers[1]) and tonumber(Numbers[2]) then
			--If everything passes, the operation is run
			
			return Operation.Func(Numbers[1], Numbers[2])
		end
	end
	
	--Couldn't calculate the number, maybe there was more than 1 operation?
	return 0
end

print(Calculate(Input))

I encourage you to look through the code and ask any questions. The above example is REALLY simple. I’ve tried to document it as much as possible.

Edit: I’ve kinda overengineered this example, now that I think of it…

1 Like

It has a few errors let’s say, it takes 10 + 15 to be 853…

That’s odd, I’m getting 25. Make sure you’re only doing 1 operation, for example, 5+5, because this “calculator” can’t handle more than 1 operation, aka, 5+5-5 won’t work and it’ll just return 0.

Ok, now it works… But my goal is so it can handle more than one operator…

Actually, that would be pretty simple. You can make it calculate the number every time a new operator is added, just make sure it doesn’t take the new operator.

2 Likes

What do you mean by: “just make sure it doesn’t take the new operator?”

When the player types in an operator, the input would be “5 + 5 *”, assuming they typed the * operator. What you need to do, is change it into “5 + 5” so it can be calculated to 10, and then add the the * operator back in, changing it into “10 *”.

But, then you have to take in the order of operations because “10 * 2” is different from “5 + 10”, and the whole mess that brings. I suggest you try experimenting around with string formatting and string patterns, if you really want to be able to do multiple operations at once.

1 Like

I worked my head around this a bit and came up with this module:

local operators = { "+", "-", "*", "/", "%", "^" }

local function operate(r,o,n)
	if o == "+" then r += n
	elseif o == "-" then r -= n
	elseif o == "*" then r *= n
	elseif o == "/" then r /= n
	elseif o == "%" then r %= n
	elseif o == "^" then r ^= n
	end
	
	return r
end

local function getOperatorPos(str)
	for i,c in ipairs(str:split("")) do
		if table.find(operators, c) then return i,c end
	end
end

local function opSplit(str)
	str ..= "+"
	local strTbl = {}
	local opCount = 0
	
	for i,c in ipairs(str:split("")) do
		if table.find(operators, c) then
			opCount += 1
			if opCount > 1 then
				table.insert(strTbl, str:sub(1, i - 1))
				str = str:sub(i, #str - 1)
			end
		end
	end
	if not strTbl[1] then strTbl[1] = str end
	
	return strTbl
end

local function calculate(str, res)
	local opPos, op = getOperatorPos(str)
	if not opPos then return end
	
	local num1 = opPos == 1 and res or tonumber(str:sub(1, opPos - 1))
	local num2 = tonumber(str:sub(opPos + 1, #str))
	if not num1 or not num2 then return end
	
	return operate(num1, op, num2)
end

return function(str)
	assert(typeof(str) == "string", "Invalid format, string expected")
	
	str = string.gsub(str, " ", "")
	local result
	
	local strTbl = opSplit(str)
	for _,s in ipairs(strTbl) do
		local opRes = calculate(s, result)
		if not opRes then break end
		result = opRes
	end

	return result
end

However I’m quite disappointed for not being able to figure out how to make it follow PEMDAS lol

Example code:

local calculator = require(game:GetService("ReplicatedStorage").Calculator)
print(calculator("10/2+3"))

image

1 Like

One issue though 0V, it says invalid arguments for this

require(game:GetService("ReplicatedStorage").Calculator)

It is spelled right too…