Convert calculator numbers from/to user locale.

Tries to convert numbers in query string to invariant culture format before passing to YAMP, and the other way around when presenting result from
YAMP. Nothing fancy, just a regular expression scanning for substrings consisting of number, decimal separator and group separator, trying a
parse and convert on them. Translation is skipped if no conversion between user locale and invariant culture number format is necessary.

Closes #436.
This commit is contained in:
martian-f
2017-04-10 23:43:23 +02:00
parent 16531653ab
commit 0862326a79
3 changed files with 120 additions and 18 deletions

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Windows;
@@ -20,6 +21,7 @@ namespace Wox.Plugin.Caculator
private static Regex regBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled);
private static ParseContext yampContext;
private PluginInitContext context { get; set; }
private NumberTranslator _numberTranslator;
static Main()
{
@@ -36,34 +38,37 @@ namespace Wox.Plugin.Caculator
try
{
var result = yampContext.Run(query.Search);
var result = yampContext.Run(this._numberTranslator?.Translate(query.Search) ?? query.Search);
if (result.Output != null && !string.IsNullOrEmpty(result.Result))
{
string resultValue = this._numberTranslator?.TranslateBack(result.Result) ?? result.Result;
return new List<Result>
{ new Result
{
Title = result.Result,
IcoPath = "Images/calculator.png",
Score = 300,
SubTitle = "Copy this number to the clipboard",
Action = c =>
{
new Result
{
try
Title = resultValue,
IcoPath = "Images/calculator.png",
Score = 300,
SubTitle = "Copy this number to the clipboard",
Action = c =>
{
Clipboard.SetText(result.Result);
return true;
}
catch (ExternalException e)
{
MessageBox.Show("Copy failed, please try later");
return false;
try
{
Clipboard.SetText(resultValue);
return true;
}
catch (ExternalException e)
{
MessageBox.Show("Copy failed, please try later");
return false;
}
}
}
} };
};
}
}
catch
{}
{ }
return new List<Result>();
}
@@ -90,6 +95,7 @@ namespace Wox.Plugin.Caculator
public void Init(PluginInitContext context)
{
this.context = context;
this._numberTranslator = NumberTranslator.Create(CultureInfo.CurrentCulture, CultureInfo.InvariantCulture);
}
public string GetTranslatedPluginTitle()

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Wox.Plugin.Caculator
{
/// <summary>
/// Tries to convert all numbers in a text from one culture format to another.
/// </summary>
public class NumberTranslator
{
private readonly CultureInfo sourceCulture;
private readonly CultureInfo targetCulture;
private readonly Regex splitRegexForSource;
private readonly Regex splitRegexForTarget;
private NumberTranslator(CultureInfo sourceCulture, CultureInfo targetCulture)
{
this.sourceCulture = sourceCulture;
this.targetCulture = targetCulture;
this.splitRegexForSource = GetSplitRegex(this.sourceCulture);
this.splitRegexForTarget = GetSplitRegex(this.targetCulture);
}
/// <summary>
/// Create a new <see cref="NumberTranslator"/> - returns null if no number conversion
/// is required between the cultures.
/// </summary>
/// <param name="sourceCulture">source culture</param>
/// <param name="targetCulture">target culture</param>
/// <returns></returns>
public static NumberTranslator Create(CultureInfo sourceCulture, CultureInfo targetCulture)
{
bool conversionRequired = sourceCulture.NumberFormat.NumberDecimalSeparator != targetCulture.NumberFormat.NumberDecimalSeparator
|| sourceCulture.NumberFormat.PercentGroupSeparator != targetCulture.NumberFormat.PercentGroupSeparator
|| sourceCulture.NumberFormat.NumberGroupSizes != targetCulture.NumberFormat.NumberGroupSizes;
return conversionRequired
? new NumberTranslator(sourceCulture, targetCulture)
: null;
}
/// <summary>
/// Translate from source to target culture.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public string Translate(string input)
{
return this.Translate(input, this.sourceCulture, this.targetCulture, this.splitRegexForSource);
}
/// <summary>
/// Translate from target to source culture.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public string TranslateBack(string input)
{
return this.Translate(input, this.targetCulture, this.sourceCulture, this.splitRegexForTarget);
}
private string Translate(string input, CultureInfo cultureFrom, CultureInfo cultureTo, Regex splitRegex)
{
var outputBuilder = new StringBuilder();
string[] tokens = splitRegex.Split(input);
foreach (string token in tokens)
{
decimal number;
outputBuilder.Append(
decimal.TryParse(token, NumberStyles.Number, cultureFrom, out number)
? number.ToString(cultureTo)
: token);
}
return outputBuilder.ToString();
}
private Regex GetSplitRegex(CultureInfo culture)
{
var splitPattern = $"((?:\\d|{Regex.Escape(culture.NumberFormat.NumberDecimalSeparator)}";
if (!string.IsNullOrEmpty(culture.NumberFormat.NumberGroupSeparator))
{
splitPattern += $"|{Regex.Escape(culture.NumberFormat.NumberGroupSeparator)}";
}
splitPattern += ")+)";
return new Regex(splitPattern);
}
}
}

View File

@@ -51,6 +51,7 @@
<Compile Include="..\..\SolutionAssemblyInfo.cs">
<Link>Properties\SolutionAssemblyInfo.cs</Link>
</Compile>
<Compile Include="NumberTranslator.cs" />
<Compile Include="Main.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>