Open djvar94 opened 4 years ago
@WK-GiHu Now I'm getting this warning in the console
result = buffer.set_buffer(calculation)
AttributeError: 'TextBuffer' object has no attribute 'set_buffer'
@WK-GiHu
Hang on, obviously I'm thinking after the expression has been evaluated and therefore done the result will have to be converted from a number (preferably long type) to a string so I'm thinking
calculation = str(eval(expression))
@djvar94
operators = {"+": operator.add, "-": operator.sub, "x": operator.mul, "÷": operator.truediv, "%": operator.mod}
expression = expression.replace('÷', '/')
modulo
but didn't you want it as percent
?
AttributeError: 'TextBuffer' object has no attribute 'set_buffer'
Why don't you use your allready used:
buffer.insert_at_cursor(...
To clear the TextBuffer
do:
buffer.delete(start, end)
have to be converted from a number (preferably long type) to a string so I'm thinking calculation = str(eval(expression))
Yes, looks OK.
@WK-GiHu Oh yeah. Lol I don't know why I haven't thought of that before about the +, - and insert_at_cursor 😄. Thank you very much nevertheless for your help, I'll give that a try perhaps tomorrow..
@WK-GiHu By the way yes, I am trying to do % as (num1 ± num2%)
@WK-GiHu
yes, I am trying to do
%
as(num1 ± num2%)
Don't get the meaning of ±
?
But either way, you have to replace num%
with the base Python mat, e.g
100%10 => 100*0.10
.replace('%10', '*0.10')
or
100%10 => 100/100*10
.replace('%10', /100*10')
This requires to slice the relevant part, %10
from the expression string, compute and then replace it.
Read up on: module-re
Another approach is, to split the whole expression
string into single parts and compute this single parts one by one in a chain. E.g.:
100+200/3%10 => [100, '+', 200, '/', 3, '%', 10]
v = 0.0
op = None
for x in [100, '+', 200, '/', 3, '%', 10]:
if x in '+-/':
op = <operater_function x>
else:
if x == '%':
op = <operater_function %>
else:
v = float(x)
if op is not None:
v = op(v, x)
op = None
This becomes more an more complex if you have to obey math orders or groups by ()
.
I can imagin, there is already a Python module available which parse a expression string an give the result back.
@WK-GiHu By ± I mean + or - say for example 100 - 25% = 75 or if the user puts a + instead of a minus then Python would have to add 25% rather than subtracting it of course, so it would be 100 + 25% = 125.
Seems a bit complicated all that other example you've given, I'm sure too there's probably a module already but will try and give some experimentation nevertheless.
Anyway, changing topic for a little bit, I was just thinking about a project I was working on some months ago that then I gave up because it was far too complicated for me to understand. It was a fun project of a gtk text spammer on Linux but I don't seem to understand how I could have grabbed the focus of any other Linux program that can accept text input say like Firefox, Chrome/Chromium or even gedit, etc etc. Do you know by any chance if that is possible to grab another program's focus from click even in gtk/Python programming? I know this is off topic, but just wanted to know if it's possible or not, tried to ask on stacked change too but got no answer...
@WK-GiHu Ok, so I have fixed every operator except for %
. That one seems to be a bit tricky for me as it would require a special function dedicated to an operation like num1 - (or +) num2%. Only thing though is that for Python that is not a valid syntax so I've got to use some other way to let the Python interpreter know I want to do that operation somehow.
I have updated the code by the way, I'm also thinking of adding (
and )
buttons to the UI for the expression and a back like <--
button to delete one character at a time from the expression field.
Anyway, I have tried to copy and paste that code
100%10 => 1000.10 .replace('%10', '0.10')
and
100+200/3%10 => [100, '+', 200, '/', 3, '%', 10]
v = 0.0
for x in [100, '+', 200, '/', 3, '%', 10]:
if x in '+-/':
op = <operator_function x>
else:
if x == '%':
op = <operator_function %>
else:
v = float(x)
if op is not None:
v = op(v, x)
op = None
but it didn't work, I got so many red lines and stuff...:(
@djvar94
Ok, so I have fixed every operator except for %.
Looks OK
That one seems to be a bit tricky
Yes, you have top split before and after 'xx%'
, eval the left part, eval the 'xx%'
part and than eval both subparts.
By ± I mean + or - say for example 100 - 25% = 75
Ah, yes, makes sense. Therefore you have to adapt the chain logic accordinly.
but it didn't work, I got so many red lines and stuff...:(
Yes, it's not a working example. It's only PSEYDOCODE to show the approach in general.
@WK-GiHu right ok.
Yes, you have top split before and after 'xx%', eval the left part, eval the 'xx%' part and than eval both subparts.
The only thing though is how do I split the factors on a variable expression given by the user, is there some sort of loop (like a for
loop) I can implement to go through the expression and make the separation automatically, eval them separately and then put them together and eval them again all together?
I don't know how to split the expression :/
Usually when it comes to percentage I do (factor /100 *(percentageNumber))
and I get the actual percentage but in this example I don't think it works.
@djvar94
what about SymPy? Do you think it would be any use?
Didn't find a percent usage example.
Also didn't find a simple 100 + 200
example.
As i understand the use of variables
like x
is required.
I'm unsure to tell about it ...
The only thing though is how do I split the factors on a variable expression given by the user
Post a example string expression, i would like to extend my PSEUDOCODE to a working example.
@WK-GiHu Ok, will try that.
@WK-GiHu OMG I have just found an answer to another guy's questions on how to use % in Python on Stack Exchange and I quote this guy
def percent(expression):
if "%" in expression:
expression = expression.replace("%","/100")
return eval(expression)
>>> percent("1500*20%")
300.0
I think this could really work. Will try it maybe tomorrow on my code..
@djvar94
expression.replace("%","/100")
Yes, very simple solution. Give it a try.
@WK-GiHu I picked up MATE Calculator to test out the formula first and while that works for multiplication and division, it doesn't work for addition and subtraction, so it's ok for things like 1500x20%
or 1500÷20%
but not for 1500+20%
or 1500-20%
. +
or -
don't return the same result as if you did it on the calculator normally..
@djvar94
1500+20% or 1500-20%. + or - don't return the same result as if you did it on the calculator normally
1500÷20%
should also fail
Expand it to: 1500+20/100
, this evaluated to:
1500x20% => 1500x20/100
Should work if you write: 1500-(20%)
, but it's errorprone to obey such rules.
@WK-GiHu well. Again with MATE Calculator even putting parenthesis in doesn't change anything obvious as in maths multiplication and division get executed before additions and subtractions. So it would execute the calculation inside the parenthesis first and then take that result and do the subtraction. The results with + and - that you report are exactly what I get too. It doesn't add 20% it only adds 0.2. is there perhaps another formula to replace to the %
that would work both for x
, ÷
and +
, -
?
@WK-GiHu
Should work if you write: 1500-(20%), but it's errorprone to obey such rules.
Just tried on my phone it gives the same result as if you did 1500-20/100
. It instead gives the correct result of you write it 1500-20%
without parenthesis.
@djvar94
another formula to replace to the % that would work
Should work if you write: 1500-(20%), but it's errorprone to obey such rules. Just tried ...
If you meant: Subtract 20%
of 1500
from 1500
, then it will fail.
But, 1500-(20/100)
should compute OK.
Therefore man have to clarify the meaning of: x - y%
@WK-GiHu Ok, I've updated the code with the expression = expression.replace('%', '/100')
and now it does return the correct result ONLY WHEN DOING THE OPERATION IN PARENTHESIS (eg. 1500÷(20%), if I do it without the parenthesis it's completely wrong...NOT THE SAME for multiplication though. And + and - are a no no.
So maybe what I'm thinking to do is to say to Python, if there is a * operator before the percentage then behave in a way, otherwise do something else, but it's kind of tricky....why couldn't programmers just assign a damn operator for percentages already. Why have they got to make this simple thing such a hell?
@WK-GiHu I think I could add the slicing operator, have a look on this page and scroll down until you see the slicing in the table. operator --- Standard Operators as functions
@WK-GiHu
Have a look at Order of operations Common_operator_notation Reverse_Polish_notation Percentage List_of_algorithms#Parsing Operator-precedence_parser
I'm afraid this doesn't help me at all as I already knew most of it. I just thought maybe a way to split the expression
string into (float) numbers and their respective operators so maybe if we can treat each number individually I can apply the percentage formula better.
@djvar94
a way to split the expression string into (float) numbers and their respective operators
This is described in Reverse_Polish_notation
, List_of_algorithms#Parsing
and Operator-precedence_parser
.
Also my proposal here: https://github.com/djvar94/gtk-simple-calculator-python3/issues/7#issuecomment-595824791
found this in the meantime anyway, might help
It's the Python build-in split()
, this can handle only split by one single chr
.
More powerfull, but also more complicated usage, are: module-re.
The re.split(...
allows a string expression, e.g. 5x5 + 2 / 3÷2+ 10 % - 1
, to be splitted to:
[('', '5', ''), ('*', '5', ''), ('+', '2', ''), ('/', '3', ''), ('÷', '2', ''), ('+', '10', ' %'), ('-', '1', '')]
@WK-GiHu oh ok, yes, forgot about your example, will have to give that a try.
I see the use of re.split()
, thank you for that.
@WK-GiHu Ok, so I tried to test the code that you gave me and I get this. The red underline says: "[pyflakes] invalid syntax"
@WK-GiHu Ok. Some bits were kind of complicated, that pseudocode was not too easy to understand, I sort of get what it does but I certainly wouldn't have been able to get through it on my own, at least not with the knowledge of Python that I have at the moment. I saw your pull request and think I get what it's doing. Will have to get inspiration and try to see if I can make it in my code too. My thought was to define the eval function manually so that it can work with the percentage like you did in your bit. Thanks anyway :) will keep you informed.
@WK-GiHu Ok so I followed your pull request and I have updated my code. Now all the calculations are weird. For example if I do 100-20 it should return 80 but I get -20 instead. For addition if I do 100+20 I get 20, if I do 100x20 I get 0.0, if I do 100/20 I get 0.0 and if I do 100-20% I get -0.2. Don't really know why..
@djvar94
Now all the calculations are weird.
Yes, can reproduce this.
The regex
fail if the expession starts with more than one digit.
Can't explain why, because the used (\d+)
should grab as many digits up to the next none digit. But it results with ('1', '00', '')
which gives 0
as start value instead of 100
.
OK, i have changed the regex to start always with digits.
See my updated Pull Request, you have to exchange the whole def eval(...
@WK-GiHu Thanks mate, will give it a try
@WK-GiHu Ok so I have tried the code and now everything works correctly except for the famous %
.
If I do 1500-20%
it returns instead of the correct value that should be 1200 it now returns 14.8
.
(I have updated the code based on your pull request commit number 2)
Also if I do 1500-%20
instead of returning the error popup for malformed expression like it should it gives a result (0.1497005988023952
)
@djvar94
everything works correctly except for the famous %.
As i mentiniod earlier, first you have to define the rule. Example: 100 - 10% Do you want: left value minus percent == 100 - 0.1 or do you want: left value minus (left value percent) == 100 - (1000.1)
@WK-GiHu Well of course I want as the expression states: left value minus (or plus or whatever) the right value. So yeah, definitively the second example scenario 100 - (100*0.1)
@djvar94
So yeah, definitively the second example scenario 100 - (100*0.1)
Try, didn't verify it:
r = op(r, mul(r, (float(v[2]) / 100)))
@WK-GiHu Nope, still doesn't work. For 100-20%
it returns 0.8
instead of 80.
@djvar94
Hmm, i get 80.0
e:[('100', '', '', ''), ('-20%', '-', '20', '%')]
r:100.0
r:80.0
buffer:('100-20%', '80.0')
Have you replaced the one in the %
branche?
Have you replaced the one in the % branche?
@WK-GiHu Yes, I did. That's the only one I replaced.
@WK-GiHu uh that is interesting. Whilst it does good with few numbers, I have tried to make a calculation with many factors and operators (but not %
) and I get a totally wrong number. In fact the result should even be a negative number, instead I get a really high positive one. You can try it yourself on any good calculator, : 100+30-40x16÷3+45+54-13x28 the result should be −348.333333333 I instead get 15848.0 it seems like it gets confused when you use different operators in the expression
@djvar94
I get a totally wrong number
Different calculators follow different orders of operations. Read Calculators
This simple calculator is working left to right without any priority given to different operators.
Therefore you get 15848.0
Your good calculator uses: 100+30-(40x16)÷3+45+54-(13x28)
Results in: −348.333333333
@WK-GiHu I see. Although when I was using normal eval (without defining eval function manually) it was doing that alright with correct operator prevalence, only the %
wasn't working. That's what I've been trying to fix :(
@djvar94
You have to implement: orders of operations.
Have a look at GitHub - plusminus,
there is a ready to use example BusinessParser with %
operator
Removed manual eval definition as not working correctly as a calculator should, reverted back to normal eval function
@Wk-GiHu So I have the operator module imported in my program. I have seen somewhere online someone who suggested to use a dictionary assigning the symbols to the operator functions. So it would be
operators = {"+": operator.add, "-": operator.sub, "x": operator.mul, "÷": operator.truediv, "%": operator.mod}
So I'm trying to figure how to then convert the symbols from the given user expression to operators that Python can actually understand.