mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
* fixes #20187 * handles PR reviews - fix some typos - updated dev docs - added PR examples to tests - improve method naming style * Fix typo Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com> --------- Co-authored-by: José Javier Rodríguez Zas <jj.jobs2live@outlook.com> Co-authored-by: Stefan Markovic <57057282+stefansjfw@users.noreply.github.com>
189 lines
5.9 KiB
C#
189 lines
5.9 KiB
C#
// Copyright (c) Microsoft Corporation
|
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
using System;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
|
{
|
|
public static class CalculateHelper
|
|
{
|
|
private static readonly Regex RegValidExpressChar = new Regex(
|
|
@"^(" +
|
|
@"%|" +
|
|
@"ceil\s*\(|floor\s*\(|exp\s*\(|max\s*\(|min\s*\(|abs\s*\(|log(?:2|10)?\s*\(|ln\s*\(|sqrt\s*\(|pow\s*\(|" +
|
|
@"factorial\s*\(|sign\s*\(|round\s*\(|rand\s*\(|" +
|
|
@"sin\s*\(|cos\s*\(|tan\s*\(|arcsin\s*\(|arccos\s*\(|arctan\s*\(|" +
|
|
@"sinh\s*\(|cosh\s*\(|tanh\s*\(|arsinh\s*\(|arcosh\s*\(|artanh\s*\(|" +
|
|
@"pi|" +
|
|
@"==|~=|&&|\|\||" +
|
|
@"e|[0-9]|0x[0-9a-fA-F]+|0b[01]+|[\+\-\*\/\^\., ""]|[\(\)\|\!\[\]]" +
|
|
@")+$",
|
|
RegexOptions.Compiled);
|
|
|
|
public static bool InputValid(string input)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(input))
|
|
{
|
|
throw new ArgumentNullException(paramName: nameof(input));
|
|
}
|
|
|
|
if (!RegValidExpressChar.IsMatch(input))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!BracketHelper.IsBracketComplete(input))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// If the input ends with a binary operator then it is not a valid input to mages and the Interpret function would throw an exception. Because we expect here that the user has not finished typing we block those inputs.
|
|
string trimmedInput = input.TrimEnd();
|
|
if (trimmedInput.EndsWith('+') || trimmedInput.EndsWith('-') || trimmedInput.EndsWith('*') || trimmedInput.EndsWith('|') || trimmedInput.EndsWith('\\') || trimmedInput.EndsWith('^') || trimmedInput.EndsWith('=') || trimmedInput.EndsWith('&') || trimmedInput.EndsWith('/') || trimmedInput.EndsWith('%'))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static string FixHumanMultiplicationExpressions(string input)
|
|
{
|
|
var output = CheckNumberOrConstantThenParenthesisExpr(input);
|
|
output = CheckNumberOrConstantThenFunc(output);
|
|
output = CheckParenthesisExprThenFunc(output);
|
|
output = CheckParenthesisExprThenParenthesisExpr(output);
|
|
output = CheckNumberThenConstant(output);
|
|
output = CheckConstantThenConstant(output);
|
|
return output;
|
|
}
|
|
|
|
/*
|
|
* num (exp)
|
|
* const (exp)
|
|
*/
|
|
private static string CheckNumberOrConstantThenParenthesisExpr(string input)
|
|
{
|
|
var output = input;
|
|
do
|
|
{
|
|
input = output;
|
|
output = Regex.Replace(input, @"(\d+|pi|e)\s*(\()", m =>
|
|
{
|
|
if (m.Index > 0 && char.IsLetter(input[m.Index - 1]))
|
|
{
|
|
return m.Value;
|
|
}
|
|
|
|
return $"{m.Groups[1].Value} * {m.Groups[2].Value}";
|
|
});
|
|
}
|
|
while (output != input);
|
|
|
|
return output;
|
|
}
|
|
|
|
/*
|
|
* num func
|
|
* const func
|
|
*/
|
|
private static string CheckNumberOrConstantThenFunc(string input)
|
|
{
|
|
var output = input;
|
|
do
|
|
{
|
|
input = output;
|
|
output = Regex.Replace(input, @"(\d+|pi|e)\s*([a-zA-Z]+[0-9]*\s*\()", m =>
|
|
{
|
|
if (input[m.Index] == 'e' && input[m.Index + 1] == 'x' && input[m.Index + 2] == 'p')
|
|
{
|
|
return m.Value;
|
|
}
|
|
|
|
if (m.Index > 0 && char.IsLetter(input[m.Index - 1]))
|
|
{
|
|
return m.Value;
|
|
}
|
|
|
|
return $"{m.Groups[1].Value} * {m.Groups[2].Value}";
|
|
});
|
|
}
|
|
while (output != input);
|
|
|
|
return output;
|
|
}
|
|
|
|
/*
|
|
* (exp) func
|
|
* func func
|
|
*/
|
|
private static string CheckParenthesisExprThenFunc(string input)
|
|
{
|
|
var p = @"(\))\s*([a-zA-Z]+[0-9]*\s*\()";
|
|
var r = "$1 * $2";
|
|
return Regex.Replace(input, p, r);
|
|
}
|
|
|
|
/*
|
|
* (exp) (exp)
|
|
* func (exp)
|
|
*/
|
|
private static string CheckParenthesisExprThenParenthesisExpr(string input)
|
|
{
|
|
var p = @"(\))\s*(\()";
|
|
var r = "$1 * $2";
|
|
return Regex.Replace(input, p, r);
|
|
}
|
|
|
|
/*
|
|
* num const
|
|
*/
|
|
private static string CheckNumberThenConstant(string input)
|
|
{
|
|
var output = input;
|
|
do
|
|
{
|
|
input = output;
|
|
output = Regex.Replace(input, @"(\d+)\s*(pi|e)", m =>
|
|
{
|
|
if (m.Index > 0 && char.IsLetter(input[m.Index - 1]))
|
|
{
|
|
return m.Value;
|
|
}
|
|
|
|
return $"{m.Groups[1].Value} * {m.Groups[2].Value}";
|
|
});
|
|
}
|
|
while (output != input);
|
|
|
|
return output;
|
|
}
|
|
|
|
/*
|
|
* const const
|
|
*/
|
|
private static string CheckConstantThenConstant(string input)
|
|
{
|
|
var output = input;
|
|
do
|
|
{
|
|
input = output;
|
|
output = Regex.Replace(input, @"(pi|e)\s*(pi|e)", m =>
|
|
{
|
|
if (m.Index > 0 && char.IsLetter(input[m.Index - 1]))
|
|
{
|
|
return m.Value;
|
|
}
|
|
|
|
return $"{m.Groups[1].Value} * {m.Groups[2].Value}";
|
|
});
|
|
}
|
|
while (output != input);
|
|
|
|
return output;
|
|
}
|
|
}
|
|
}
|