Review feedback, case insensitive, consistent separators

This commit is contained in:
dcog989 2025-09-14 21:51:47 +01:00
parent e990e0ff5b
commit edc76faeb4
2 changed files with 46 additions and 28 deletions

View file

@ -52,8 +52,15 @@ namespace Flow.Launcher.Plugin.Calculator
try try
{ {
bool isFunctionPresent = FunctionRegex.IsMatch(query.Search); var search = query.Search;
var expression = NumberRegex.Replace(query.Search, m => NormalizeNumber(m.Value, isFunctionPresent)); bool isFunctionPresent = FunctionRegex.IsMatch(search);
// Mages is case sensitive, so we need to convert all function names to lower case.
search = FunctionRegex.Replace(search, m => m.Value.ToLowerInvariant());
var decimalSep = GetDecimalSeparator();
var groupSep = GetGroupSeparator(decimalSep);
var expression = NumberRegex.Replace(search, m => NormalizeNumber(m.Value, isFunctionPresent, decimalSep, groupSep));
// WORKAROUND START: The 'pow' function in Mages v3.0.0 is broken. // WORKAROUND START: The 'pow' function in Mages v3.0.0 is broken.
// https://github.com/FlorianRappl/Mages/issues/132 // https://github.com/FlorianRappl/Mages/issues/132
@ -185,48 +192,56 @@ namespace Flow.Launcher.Plugin.Calculator
return $"({arg1}^{arg2})"; return $"({arg1}^{arg2})";
} }
private static string NormalizeNumber(string numberStr, bool isFunctionPresent) private static string NormalizeNumber(string numberStr, bool isFunctionPresent, string decimalSep, string groupSep)
{ {
var culture = CultureInfo.CurrentCulture;
var groupSep = culture.NumberFormat.NumberGroupSeparator;
var decimalSep = culture.NumberFormat.NumberDecimalSeparator;
if (isFunctionPresent) if (isFunctionPresent)
{ {
// STRICT MODE: When functions are present, ',' is ALWAYS an argument separator. // STRICT MODE: When functions are present, ',' is ALWAYS an argument separator.
// It must not be normalized.
if (numberStr.Contains(',')) if (numberStr.Contains(','))
{ {
return numberStr; return numberStr;
} }
// The string has no commas. It could have a '.' group separator (e.g. in de-DE) string processedStr = numberStr;
// or a '.' decimal separator (e.g. in en-US).
// Since Mages' decimal separator is '.', we only need to strip the group separator. // Handle group separator, with special care for ambiguous dot.
if (groupSep == ".") if (!string.IsNullOrEmpty(groupSep))
{ {
var parts = numberStr.Split('.'); if (groupSep == ".")
// A number with a dot group separator, e.g., "1.234"
if (parts.Length > 1)
{ {
// Check if the parts after the first dot have the correct group length (usually 3). var parts = processedStr.Split('.');
for (int i = 1; i < parts.Length; i++) if (parts.Length > 1)
{ {
if (parts[i].Length != 3) bool isGrouped = true;
for (var i = 1; i < parts.Length; i++)
{ {
// Malformed grouping, e.g., "1.23". This is likely a decimal number. if (parts[i].Length != 3)
// Return as is and let Mages handle it. {
return numberStr; isGrouped = false;
break;
}
} }
if (isGrouped)
{
processedStr = processedStr.Replace(groupSep, "");
}
// If not grouped, it's likely a decimal number, so we don't strip dots.
} }
// Correct grouping, e.g., "1.234" or "1.234.567". Strip separators. }
return numberStr.Replace(".", ""); else
{
processedStr = processedStr.Replace(groupSep, "");
} }
} }
// For any other case (e.g. en-US culture where group sep is ',' which was already handled), // Handle decimal separator.
// return the string as is. if (decimalSep != ".")
return numberStr; {
processedStr = processedStr.Replace(decimalSep, ".");
}
return processedStr;
} }
else else
{ {
@ -236,7 +251,10 @@ namespace Flow.Launcher.Plugin.Calculator
{ {
processedStr = processedStr.Replace(groupSep, ""); processedStr = processedStr.Replace(groupSep, "");
} }
processedStr = processedStr.Replace(decimalSep, "."); if (decimalSep != ".")
{
processedStr = processedStr.Replace(decimalSep, ".");
}
return processedStr; return processedStr;
} }
} }

View file

@ -10,7 +10,7 @@ internal static partial class MainRegexHelper
[GeneratedRegex(@"\B(?=(\d{3})+(?!\d))", RegexOptions.Compiled)] [GeneratedRegex(@"\B(?=(\d{3})+(?!\d))", RegexOptions.Compiled)]
public static partial Regex GetThousandGroupRegex(); public static partial Regex GetThousandGroupRegex();
[GeneratedRegex(@"\bpow(\((?:[^()\[\]]|\((?<Depth>)|\)(?<-Depth>)|\[(?<Depth>)|\](?<-Depth>))*(?(Depth)(?!))\))", RegexOptions.Compiled | RegexOptions.RightToLeft)] [GeneratedRegex(@"\bpow(\((?:[^()\[\]]|\((?<Depth>)|\)(?<-Depth>)|\[(?<Depth>)|\](?<-Depth>))*(?(Depth)(?!))\))", RegexOptions.Compiled | RegexOptions.RightToLeft | RegexOptions.IgnoreCase)]
public static partial Regex GetPowRegex(); public static partial Regex GetPowRegex();
[GeneratedRegex(@"\b(sqrt|pow|factorial|abs|sign|ceil|floor|round|exp|log|log2|log10|min|max|lt|eq|gt|sin|cos|tan|arcsin|arccos|arctan|isnan|isint|isprime|isinfty|rand|randi|type|is|as|length|throw|catch|eval|map|clamp|lerp|regex|shuffle)\s*\(", RegexOptions.Compiled | RegexOptions.IgnoreCase)] [GeneratedRegex(@"\b(sqrt|pow|factorial|abs|sign|ceil|floor|round|exp|log|log2|log10|min|max|lt|eq|gt|sin|cos|tan|arcsin|arccos|arctan|isnan|isint|isprime|isinfty|rand|randi|type|is|as|length|throw|catch|eval|map|clamp|lerp|regex|shuffle)\s*\(", RegexOptions.Compiled | RegexOptions.IgnoreCase)]