Fix calculator comma decimal parsing#47528
Conversation
daverayment
left a comment
There was a problem hiding this comment.
Thanks for tackling this. From what I can tell from the code, you have a new NumberTranslator.TryParseCommandDecimal() method which is used when the current culture uses . as the decimal separator, and attempts to reinterpret a comma-separated number token as a decimal number based on the following heuristic:
- One comma only
- Not at the start/end of a token
- Not exactly 3 digits after the comma. These cases are assumed to instead refer to numbers split by a thousands separator like
1,234.
Unfortunately, there are several issues with a solution purely based on string-level heuristics.
The core issue is that commas become inherently ambiguous. They can mean three different things simultaneously:
- A decimal separator, e.g.
1,5meaning1.5 - A thousands/grouping separator, e.g.
2,000meaning2000 - A function argument separator, e.g.
max(2,6)
(Actually, it seems that multi-argument functions are currently broken with comma separators before this PR. It seems that NumberTranslator consumes the comma as a thousands separator before passing on the expression to ExprTK. I'll raise this separately.)
Also, if a number with three digits after a comma is always assumed to have a thousands separator, this means users with . decimal separators cannot type decimals with three digits of precision with the comma - "123,000" is always interpreted as "123000" and never "123.0".
No string-level heuristic can reliably disambiguate these, as it doesn't have knowledge of the entire expression. We could potentially choose a different separator character for functions (; is often used as a separator for precisely this reason in European calculators, for example), but I think that's beyond the scope for this PR.
Without structural changes to how argument and decimal separators are distinguished, I don't think a reliable fix is achievable through string manipulation on its own.
Summary of the Pull Request
Fixes Command Palette Calculator handling for comma decimal input such as
1,5+1,5, so it evaluates as3instead of treating each value as15.Also adds explicit regression coverage for PowerToys Run Calculator inputs without leading zeroes, such as
.76*2.4and-.5*2.PR Checklist
Detailed Description of the Pull Request / Additional comments
Command Palette Calculator translated comma-separated numbers using the current culture parsing rules. In cultures where
.is the decimal separator and,is the group separator, input like1,5+1,5could be interpreted as15+15, returning30.This PR adds a narrow fallback in the CmdPal calculator number translator:
1,5+1,5is translated as1.5+1.5.-1,5+2is translated as-1.5+2.1,000+2continue to be treated as thousands and translate to1000+2.This also adds regression tests for PowerToys Run Calculator inputs without leading zeroes:
.76*2.4-.5*2Validation Steps Performed
tools\build\build.cmd -Path src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.Calc.UnitTests321/321passedtools\build\build.cmd -Path src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.Calculator.UnitTest366/366passedtools\build\build-essentials.cmd