onboarding stylecop (#5622)

This commit is contained in:
Clint Rutkas
2020-08-04 16:39:25 -07:00
committed by GitHub
parent 010732108c
commit a793cf4ac2
3 changed files with 413 additions and 385 deletions

View File

@@ -1,181 +1,193 @@
using System; // Copyright (c) Microsoft Corporation
using System.Collections.Generic; // The Microsoft Corporation licenses this file to you under the MIT license.
using System.Drawing; // See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
using System.Text.RegularExpressions; using System;
using System.Threading; using System.Collections.Generic;
using System.Windows; using System.Runtime.InteropServices;
using Mages.Core; using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using Mages.Core;
using Wox.Infrastructure.Logger; using Wox.Infrastructure.Logger;
using Wox.Plugin; using Wox.Plugin;
namespace Microsoft.Plugin.Calculator namespace Microsoft.Plugin.Calculator
{ {
public class Main : IPlugin, IPluginI18n, IDisposable public class Main : IPlugin, IPluginI18n, IDisposable
{ {
private static readonly Regex RegValidExpressChar = new Regex( private static readonly Regex RegValidExpressChar = new Regex(
@"^(" + @"^(" +
@"ceil|floor|exp|pi|e|max|min|det|abs|log|ln|sqrt|" + @"ceil|floor|exp|pi|e|max|min|det|abs|log|ln|sqrt|" +
@"sin|cos|tan|arcsin|arccos|arctan|" + @"sin|cos|tan|arcsin|arccos|arctan|" +
@"eigval|eigvec|eig|sum|polar|plot|round|sort|real|zeta|" + @"eigval|eigvec|eig|sum|polar|plot|round|sort|real|zeta|" +
@"bin2dec|hex2dec|oct2dec|" + @"bin2dec|hex2dec|oct2dec|" +
@"==|~=|&&|\|\||" + @"==|~=|&&|\|\||" +
@"[ei]|[0-9]|[\+\-\*\/\^\., ""]|[\(\)\|\!\[\]]" + @"[ei]|[0-9]|[\+\-\*\/\^\., ""]|[\(\)\|\!\[\]]" +
@")+$", RegexOptions.Compiled); @")+$", RegexOptions.Compiled);
private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled);
private static readonly Engine MagesEngine = new Engine(); private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled);
private PluginInitContext Context { get; set; } private static readonly Engine MagesEngine = new Engine();
private string IconPath { get; set; }
private bool _disposed = false; private PluginInitContext Context { get; set; }
public List<Result> Query(Query query) private string IconPath { get; set; }
{
if(query == null) private bool _disposed = false;
public List<Result> Query(Query query)
{
if (query == null)
{ {
throw new ArgumentNullException(paramName: nameof(query)); throw new ArgumentNullException(paramName: nameof(query));
}
if (query.Search.Length <= 2 // don't affect when user only input "e" or "i" keyword
|| !RegValidExpressChar.IsMatch(query.Search)
|| !IsBracketComplete(query.Search)) return new List<Result>();
try
{
var result = MagesEngine.Interpret(query.Search);
// This could happen for some incorrect queries, like pi(2)
if (result == null)
{
return new List<Result>();
}
if (result.ToString() == "NaN")
result = Context.API.GetTranslation("wox_plugin_calculator_not_a_number");
if (result is Function)
result = Context.API.GetTranslation("wox_plugin_calculator_expression_not_complete");
if (!string.IsNullOrEmpty(result?.ToString()))
{
return new List<Result>
{
new Result
{
Title = result.ToString(),
IcoPath = IconPath,
Score = 300,
SubTitle = Context.API.GetTranslation("wox_plugin_calculator_copy_number_to_clipboard"),
Action = c =>
{
var ret = false;
var thread = new Thread(() =>
{
try
{
Clipboard.SetText(result.ToString());
ret = true;
}
catch (ExternalException)
{
MessageBox.Show("Copy failed, please try later");
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
return ret;
}
}
};
}
} }
//We want to keep the process alive if any the mages library throws any exceptions.
if (query.Search.Length <= 2 // don't affect when user only input "e" or "i" keyword
|| !RegValidExpressChar.IsMatch(query.Search)
|| !IsBracketComplete(query.Search))
{
return new List<Result>();
}
try
{
var result = MagesEngine.Interpret(query.Search);
// This could happen for some incorrect queries, like pi(2)
if (result == null)
{
return new List<Result>();
}
if (result.ToString() == "NaN")
{
result = Context.API.GetTranslation("wox_plugin_calculator_not_a_number");
}
if (result is Function)
{
result = Context.API.GetTranslation("wox_plugin_calculator_expression_not_complete");
}
if (!string.IsNullOrEmpty(result?.ToString()))
{
return new List<Result>
{
new Result
{
Title = result.ToString(),
IcoPath = IconPath,
Score = 300,
SubTitle = Context.API.GetTranslation("wox_plugin_calculator_copy_number_to_clipboard"),
Action = c =>
{
var ret = false;
var thread = new Thread(() =>
{
try
{
Clipboard.SetText(result.ToString());
ret = true;
}
catch (ExternalException)
{
MessageBox.Show("Copy failed, please try later");
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
return ret;
},
},
};
}
} // We want to keep the process alive if any the mages library throws any exceptions.
#pragma warning disable CA1031 // Do not catch general exception types #pragma warning disable CA1031 // Do not catch general exception types
catch(Exception e) catch (Exception e)
#pragma warning restore CA1031 // Do not catch general exception types #pragma warning restore CA1031 // Do not catch general exception types
{ {
Log.Exception($"|Microsoft.Plugin.Calculator.Main.Query|Exception when query for <{query}>", e); Log.Exception($"|Microsoft.Plugin.Calculator.Main.Query|Exception when query for <{query}>", e);
} }
return new List<Result>(); return new List<Result>();
} }
private static bool IsBracketComplete(string query) private static bool IsBracketComplete(string query)
{ {
var matchs = RegBrackets.Matches(query); var matchs = RegBrackets.Matches(query);
var leftBracketCount = 0; var leftBracketCount = 0;
foreach (Match match in matchs) foreach (Match match in matchs)
{ {
if (match.Value == "(" || match.Value == "[") if (match.Value == "(" || match.Value == "[")
{ {
leftBracketCount++; leftBracketCount++;
} }
else else
{ {
leftBracketCount--; leftBracketCount--;
} }
} }
return leftBracketCount == 0; return leftBracketCount == 0;
} }
public void Init(PluginInitContext context) public void Init(PluginInitContext context)
{ {
if(context == null) if (context == null)
{ {
throw new ArgumentNullException(paramName: nameof(context)); throw new ArgumentNullException(paramName: nameof(context));
} }
Context = context; Context = context;
Context.API.ThemeChanged += OnThemeChanged; Context.API.ThemeChanged += OnThemeChanged;
UpdateIconPath(Context.API.GetCurrentTheme()); UpdateIconPath(Context.API.GetCurrentTheme());
} }
// Todo : Update with theme based IconPath // Todo : Update with theme based IconPath
private void UpdateIconPath(Theme theme) private void UpdateIconPath(Theme theme)
{ {
if (theme == Theme.Light || theme == Theme.HighContrastWhite) if (theme == Theme.Light || theme == Theme.HighContrastWhite)
{ {
IconPath = "Images/calculator.light.png"; IconPath = "Images/calculator.light.png";
} }
else else
{ {
IconPath = "Images/calculator.dark.png"; IconPath = "Images/calculator.dark.png";
} }
} }
private void OnThemeChanged(Theme _, Theme newTheme) private void OnThemeChanged(Theme currentTheme, Theme newTheme)
{ {
UpdateIconPath(newTheme); UpdateIconPath(newTheme);
} }
public string GetTranslatedPluginTitle() public string GetTranslatedPluginTitle()
{ {
return Context.API.GetTranslation("wox_plugin_calculator_plugin_name"); return Context.API.GetTranslation("wox_plugin_calculator_plugin_name");
} }
public string GetTranslatedPluginDescription() public string GetTranslatedPluginDescription()
{ {
return Context.API.GetTranslation("wox_plugin_calculator_plugin_description"); return Context.API.GetTranslation("wox_plugin_calculator_plugin_description");
} }
public void Dispose() public void Dispose()
{ {
Dispose(disposing: true); Dispose(disposing: true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (!_disposed) if (!_disposed)
{ {
if (disposing) if (disposing)
{ {
Context.API.ThemeChanged -= OnThemeChanged; Context.API.ThemeChanged -= OnThemeChanged;
_disposed = true; _disposed = true;
} }
} }
} }
} }
} }

View File

@@ -1,113 +1,113 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<ProjectGuid>{59BD9891-3837-438A-958D-ADC7F91F6F7E}</ProjectGuid> <ProjectGuid>{59BD9891-3837-438A-958D-ADC7F91F6F7E}</ProjectGuid>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Plugin.Calculator</RootNamespace> <RootNamespace>Microsoft.Plugin.Calculator</RootNamespace>
<AssemblyName>Microsoft.Plugin.Calculator</AssemblyName> <AssemblyName>Microsoft.Plugin.Calculator</AssemblyName>
<useWPF>true</useWPF> <useWPF>true</useWPF>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath> <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Calculator\</OutputPath> <OutputPath>..\..\..\..\..\x64\Debug\modules\launcher\Plugins\Microsoft.Plugin.Calculator\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion> <LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Calculator\</OutputPath> <OutputPath>..\..\..\..\..\x64\Release\modules\launcher\Plugins\Microsoft.Plugin.Calculator\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion> <LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Include="plugin.json"> <None Include="plugin.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Wox.Infrastructure\Wox.Infrastructure.csproj" /> <ProjectReference Include="..\..\Wox.Infrastructure\Wox.Infrastructure.csproj" />
<ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj" /> <ProjectReference Include="..\..\Wox.Plugin\Wox.Plugin.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Languages\en.xaml"> <Content Include="Languages\en.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Languages\zh-cn.xaml"> <Content Include="Languages\zh-cn.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Languages\zh-tw.xaml"> <Content Include="Languages\zh-tw.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Languages\de.xaml"> <Content Include="Languages\de.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Languages\pl.xaml"> <Content Include="Languages\pl.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Languages\tr.xaml"> <Content Include="Languages\tr.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" /> <PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
<PackageReference Include="Mages" Version="1.6.0"> <PackageReference Include="Mages" Version="1.6.0">
<NoWarn>NU1701</NoWarn> <NoWarn>NU1701</NoWarn>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0"> <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="System.Runtime" Version="4.3.1" /> <PackageReference Include="System.Runtime" Version="4.3.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="Images\calculator.dark.png"> <None Update="Images\calculator.dark.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -115,6 +115,20 @@
<None Update="Images\calculator.light.png"> <None Update="Images\calculator.light.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\..\codeAnalysis\GlobalSuppressions.cs">
<Link>GlobalSuppressions.cs</Link>
</Compile>
<AdditionalFiles Include="..\..\..\..\codeAnalysis\StyleCop.json">
<Link>StyleCop.json</Link>
</AdditionalFiles>
</ItemGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project> </Project>

View File

@@ -1,105 +1,107 @@
using System; // Copyright (c) Microsoft Corporation
using System.Collections.Generic; // The Microsoft Corporation licenses this file to you under the MIT license.
using System.Globalization; // See the LICENSE file in the project root for more information.
using System.Linq;
using System.Text; using System;
using System.Text.RegularExpressions; using System.Globalization;
using System.Threading.Tasks; using System.Text;
using System.Text.RegularExpressions;
namespace Microsoft.Plugin.Calculator
{ namespace Microsoft.Plugin.Calculator
/// <summary> {
/// Tries to convert all numbers in a text from one culture format to another. /// <summary>
/// </summary> /// Tries to convert all numbers in a text from one culture format to another.
public class NumberTranslator /// </summary>
{ public class NumberTranslator
private readonly CultureInfo sourceCulture; {
private readonly CultureInfo targetCulture; private readonly CultureInfo sourceCulture;
private readonly Regex splitRegexForSource; private readonly CultureInfo targetCulture;
private readonly Regex splitRegexForTarget; private readonly Regex splitRegexForSource;
private readonly Regex splitRegexForTarget;
private NumberTranslator(CultureInfo sourceCulture, CultureInfo targetCulture)
{ private NumberTranslator(CultureInfo sourceCulture, CultureInfo targetCulture)
this.sourceCulture = sourceCulture; {
this.targetCulture = targetCulture; this.sourceCulture = sourceCulture;
this.targetCulture = targetCulture;
this.splitRegexForSource = GetSplitRegex(this.sourceCulture);
this.splitRegexForTarget = GetSplitRegex(this.targetCulture); splitRegexForSource = GetSplitRegex(this.sourceCulture);
} splitRegexForTarget = GetSplitRegex(this.targetCulture);
}
/// <summary>
/// Create a new <see cref="NumberTranslator"/> - returns null if no number conversion /// <summary>
/// is required between the cultures. /// Create a new <see cref="NumberTranslator"/> - returns null if no number conversion
/// </summary> /// is required between the cultures.
/// <param name="sourceCulture">source culture</param> /// </summary>
/// <param name="targetCulture">target culture</param> /// <param name="sourceCulture">source culture</param>
/// <returns></returns> /// <param name="targetCulture">target culture</param>
public static NumberTranslator Create(CultureInfo sourceCulture, CultureInfo targetCulture) /// <returns>Number translator for target culture</returns>
{ public static NumberTranslator Create(CultureInfo sourceCulture, CultureInfo targetCulture)
{
if (sourceCulture == null) if (sourceCulture == null)
{ {
throw new ArgumentNullException(paramName:nameof(sourceCulture));
}
if (targetCulture == null)
{
throw new ArgumentNullException(paramName: nameof(sourceCulture)); throw new ArgumentNullException(paramName: nameof(sourceCulture));
} }
bool conversionRequired = sourceCulture.NumberFormat.NumberDecimalSeparator != targetCulture.NumberFormat.NumberDecimalSeparator if (targetCulture == null)
|| sourceCulture.NumberFormat.PercentGroupSeparator != targetCulture.NumberFormat.PercentGroupSeparator {
|| sourceCulture.NumberFormat.NumberGroupSizes != targetCulture.NumberFormat.NumberGroupSizes; throw new ArgumentNullException(paramName: nameof(sourceCulture));
return conversionRequired }
? new NumberTranslator(sourceCulture, targetCulture)
: null; bool conversionRequired = sourceCulture.NumberFormat.NumberDecimalSeparator != targetCulture.NumberFormat.NumberDecimalSeparator
} || sourceCulture.NumberFormat.PercentGroupSeparator != targetCulture.NumberFormat.PercentGroupSeparator
|| sourceCulture.NumberFormat.NumberGroupSizes != targetCulture.NumberFormat.NumberGroupSizes;
/// <summary> return conversionRequired
/// Translate from source to target culture. ? new NumberTranslator(sourceCulture, targetCulture)
/// </summary> : null;
/// <param name="input"></param> }
/// <returns></returns>
public string Translate(string input) /// <summary>
{ /// Translate from source to target culture.
return Translate(input, this.sourceCulture, this.targetCulture, this.splitRegexForSource); /// </summary>
} /// <param name="input">input string to translate</param>
/// <returns>translated string</returns>
/// <summary> public string Translate(string input)
/// Translate from target to source culture. {
/// </summary> return Translate(input, sourceCulture, targetCulture, splitRegexForSource);
/// <param name="input"></param> }
/// <returns></returns>
public string TranslateBack(string input) /// <summary>
{ /// Translate from target to source culture.
return Translate(input, this.targetCulture, this.sourceCulture, this.splitRegexForTarget); /// </summary>
} /// <param name="input">input string to translate back to source culture</param>
/// <returns>source culture string</returns>
private static string Translate(string input, CultureInfo cultureFrom, CultureInfo cultureTo, Regex splitRegex) public string TranslateBack(string input)
{ {
var outputBuilder = new StringBuilder(); return Translate(input, targetCulture, sourceCulture, splitRegexForTarget);
}
string[] tokens = splitRegex.Split(input);
foreach (string token in tokens) private static string Translate(string input, CultureInfo cultureFrom, CultureInfo cultureTo, Regex splitRegex)
{ {
decimal number; var outputBuilder = new StringBuilder();
outputBuilder.Append(
decimal.TryParse(token, NumberStyles.Number, cultureFrom, out number) string[] tokens = splitRegex.Split(input);
? number.ToString(cultureTo) foreach (string token in tokens)
: token); {
} decimal number;
outputBuilder.Append(
return outputBuilder.ToString(); decimal.TryParse(token, NumberStyles.Number, cultureFrom, out number)
} ? number.ToString(cultureTo)
: token);
private static Regex GetSplitRegex(CultureInfo culture) }
{
var splitPattern = $"((?:\\d|{Regex.Escape(culture.NumberFormat.NumberDecimalSeparator)}"; return outputBuilder.ToString();
if (!string.IsNullOrEmpty(culture.NumberFormat.NumberGroupSeparator)) }
{
splitPattern += $"|{Regex.Escape(culture.NumberFormat.NumberGroupSeparator)}"; private static Regex GetSplitRegex(CultureInfo culture)
} {
splitPattern += ")+)"; var splitPattern = $"((?:\\d|{Regex.Escape(culture.NumberFormat.NumberDecimalSeparator)}";
return new Regex(splitPattern); if (!string.IsNullOrEmpty(culture.NumberFormat.NumberGroupSeparator))
} {
} splitPattern += $"|{Regex.Escape(culture.NumberFormat.NumberGroupSeparator)}";
} }
splitPattern += ")+)";
return new Regex(splitPattern);
}
}
}