mossadal / math-parser

PHP parser for mathematical expressions
GNU Lesser General Public License v3.0
171 stars 38 forks source link

Support fraction shorthand operator #6

Open ghost opened 7 years ago

ghost commented 7 years ago

"1+.1" (or ".1") triggers an exception saying Unknown token 0 encountered.

Maybe add some parsing logic to say "if period, assume a zero to the left"?

So that "1+.1" is treated as "1+0.1".

Does that make sense? Or is this a bad idea? ;-)

ghost commented 7 years ago

If this is a bad idea for the general library itself, then I'll at least contribute my userland solution, for other users of this library that want to be able to parse "50*.5" notation:

// Automatically add a leading zero to any shorthand decimal notation
// (such as "125*.5"), since the math parser doesn't support leaving out
// the leading zero. We transform such notation to "125*0.5".
// Note that we DON'T convert the OTHER kind of syntax error, "1." (for
// 1.0), because that wouldn't be a shorthand, that would be a bad expr.
$expression = preg_replace( '/([^0-9]|^)\.([0-9])/', '${1}0.${2}', $expression );
mossadal commented 7 years ago

Let me think a little about this. I'm not sure I want this in the standard Lexer that is shipped. If you want this functionality, it's probably better to change the TokenDefinition for TokenType::RealNumber in the Lexer.

ghost commented 7 years ago

@mossadal I agree, I'm not sure I want it in the standard lexer either. It's sort of a lazy shorthand. I use this in a free currency converter app I wrote, and average users may want to type "$10*.4". So that's why I think my solution belongs more in userland and less in the library.

Perhaps have another TokenDefinition class that extends the regular TokenDefinition but adds support for shorthand. But then the question is what to call such an extension class (ShorthandTokenDefinition perhaps), and who would need it. I know that for my use-case, I can't expect every user to type perfect "$10*0.4" constantly. But if they were all mathematicians I could assume they would type their expressions perfectly.

So far I'm happy with the regex solution which just rewrites their expression. Works fine. So if you don't want this in the library itself then I fully understand. It's a fine balance between a library only wanting to accept proper expressions, and yet still having familiar user-shorthands (like 2(6+2) instead of 2*(6+2), and 50*.4 instead of 50*0.4). So yeah... think about where it would belong in the library, if at all. :-)

If it helps you decide: WolframAlpha takes the "glue it all for the user" approach. If you send it 2(3 it says "An attempt was made to fix mismatched parentheses, brackets, or braces." and [assumes](http://www.wolframalpha.com/input/?i=2(3 ) you meant 2(3) and uses that. And 40*.4 is evaluated as 40 * 0.4. But both of those could be user-land glue (just like mine) that is done before their math parser engine is given the proper input.

Thanks and take care!

BrianLeishman commented 5 years ago

Just a note about the regex being used, it looks like it can be way shortened to something like this

preg_replace('/(^|\D)\./', '${1}0.', $formula);

This converts .2x+(.4*.07)x into 0.2x+(0.4*0.07)x