mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
## Summary of the Pull Request - Replaced "ounce" to "usounce" and "imperialounce" for two different results ## PR Checklist - [x] **Closes:** #32841 - [x] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [x] **Localization:** All end user facing strings can be localized - [x] **Dev docs:** Added/updated - [x] **New binaries:** Added on the required places - [x] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [x] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [x] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [x] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [x] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments - Convert `ounce` to `usounce` and `imperialounce` and show the converted results <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed - Manual validation
312 lines
12 KiB
C#
312 lines
12 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.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using UnitsNet;
|
|
using Wox.Plugin;
|
|
|
|
namespace Community.PowerToys.Run.Plugin.UnitConverter
|
|
{
|
|
public static class InputInterpreter
|
|
{
|
|
private static readonly string Pattern = @"(?<=\d)(?![,.\-])(?=[\D])|(?<=[\D])(?<![,.\-])(?=\d)";
|
|
|
|
public static string[] RegexSplitter(string[] split)
|
|
{
|
|
return Regex.Split(split[0], Pattern);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Separates input like: "1ft in cm" to "1 ft in cm"
|
|
/// </summary>
|
|
public static void InputSpaceInserter(ref string[] split)
|
|
{
|
|
if (split.Length != 3)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string[] parseInputWithoutSpace = Regex.Split(split[0], Pattern);
|
|
|
|
if (parseInputWithoutSpace.Length > 1)
|
|
{
|
|
string[] firstEntryRemoved = split.Skip(1).ToArray();
|
|
string[] newSplit = new string[] { parseInputWithoutSpace[0], parseInputWithoutSpace[1] };
|
|
|
|
split = newSplit.Concat(firstEntryRemoved).ToArray();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Replaces a split input array with shorthand feet/inch notation (1', 1'2" etc) to 'x foot in cm'.
|
|
/// </summary>
|
|
public static void ShorthandFeetInchHandler(ref string[] split, CultureInfo culture)
|
|
{
|
|
if (!split[0].Contains('\'') && !split[0].Contains('\"'))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// catches 1' || 1" || 1'2 || 1'2" in cm
|
|
// by converting it to "x foot in cm"
|
|
if (split.Length == 3)
|
|
{
|
|
string[] shortsplit = RegexSplitter(split);
|
|
|
|
switch (shortsplit.Length)
|
|
{
|
|
case 2:
|
|
// ex: 1' & 1"
|
|
if (shortsplit[1] == "\'")
|
|
{
|
|
string[] newInput = new string[] { shortsplit[0], "foot", split[1], split[2] };
|
|
split = newInput;
|
|
}
|
|
else if (shortsplit[1] == "\"")
|
|
{
|
|
string[] newInput = new string[] { shortsplit[0], "inch", split[1], split[2] };
|
|
split = newInput;
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
case 4:
|
|
// ex: 1'2 and 1'2"
|
|
if (shortsplit[1] == "\'")
|
|
{
|
|
bool isNegative = shortsplit[0].StartsWith('-');
|
|
if (isNegative)
|
|
{
|
|
shortsplit[0] = shortsplit[0].Remove(0, 1);
|
|
}
|
|
|
|
bool isFeet = double.TryParse(shortsplit[0], NumberStyles.AllowDecimalPoint, culture, out double feet);
|
|
bool isInches = double.TryParse(shortsplit[2], NumberStyles.AllowDecimalPoint, culture, out double inches);
|
|
|
|
if (!isFeet || !isInches)
|
|
{
|
|
// atleast one could not be parsed correctly
|
|
break;
|
|
}
|
|
|
|
double convertedTotalInFeet = Length.FromFeetInches(feet, inches).Feet;
|
|
if (isNegative)
|
|
{
|
|
convertedTotalInFeet *= -1;
|
|
}
|
|
|
|
string[] newInput = new string[] { convertedTotalInFeet.ToString(culture), "foot", split[1], split[2] };
|
|
split = newInput;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds degree prefixes to degree units for shorthand notation. E.g. '10 c in fahrenheit' becomes '10 °c in DegreeFahrenheit'.
|
|
/// </summary>
|
|
public static void DegreePrefixer(ref string[] split)
|
|
{
|
|
switch (split[1].ToLower(CultureInfo.CurrentCulture))
|
|
{
|
|
case "celsius":
|
|
split[1] = "DegreeCelsius";
|
|
break;
|
|
|
|
case "fahrenheit":
|
|
split[1] = "DegreeFahrenheit";
|
|
break;
|
|
|
|
case "c":
|
|
split[1] = "°c";
|
|
break;
|
|
|
|
case "f":
|
|
split[1] = "°f";
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (split[3].ToLower(CultureInfo.CurrentCulture))
|
|
{
|
|
case "celsius":
|
|
split[3] = "DegreeCelsius";
|
|
break;
|
|
|
|
case "fahrenheit":
|
|
split[3] = "DegreeFahrenheit";
|
|
break;
|
|
|
|
case "c":
|
|
split[3] = "°c";
|
|
break;
|
|
|
|
case "f":
|
|
split[3] = "°f";
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The plural form "feet" is not recognized by UniteNets. Replace it with "ft".
|
|
/// </summary>
|
|
public static void FeetToFt(ref string[] split)
|
|
{
|
|
if (string.Equals(split[1], "feet", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
split[1] = "ft";
|
|
}
|
|
|
|
if (string.Equals(split[3], "feet", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
split[3] = "ft";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts spelling "kph" to "km/h"
|
|
/// </summary>
|
|
public static void KPHHandler(ref string[] split)
|
|
{
|
|
split[1] = split[1].Replace("cph", "cm/h", System.StringComparison.CurrentCultureIgnoreCase);
|
|
split[1] = split[1].Replace("kph", "km/h", System.StringComparison.CurrentCultureIgnoreCase);
|
|
split[1] = split[1].Replace("kmph", "km/h", System.StringComparison.CurrentCultureIgnoreCase);
|
|
split[1] = split[1].Replace("cmph", "cm/h", System.StringComparison.CurrentCultureIgnoreCase);
|
|
|
|
split[3] = split[3].Replace("cph", "cm/h", System.StringComparison.CurrentCultureIgnoreCase);
|
|
split[3] = split[3].Replace("kph", "km/h", System.StringComparison.CurrentCultureIgnoreCase);
|
|
split[3] = split[3].Replace("kmph", "km/h", System.StringComparison.CurrentCultureIgnoreCase);
|
|
split[3] = split[3].Replace("cmph", "cm/h", System.StringComparison.CurrentCultureIgnoreCase);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts spelling "metre" to "meter", also for centimetre and other variants
|
|
/// </summary>
|
|
public static void MetreToMeter(ref string[] split)
|
|
{
|
|
split[1] = split[1].Replace("metre", "meter", System.StringComparison.CurrentCultureIgnoreCase);
|
|
split[3] = split[3].Replace("metre", "meter", System.StringComparison.CurrentCultureIgnoreCase);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Choose "UsGallon" or "ImperialGallon" according to current culture when the input contains "gal" or "gallon".
|
|
/// </summary>
|
|
public static void GallonHandler(ref string[] split, CultureInfo culture)
|
|
{
|
|
HashSet<string> britishCultureNames = new HashSet<string>() { "en-AI", "en-VG", "en-GB", "en-KY", "en-MS", "en-AG", "en-DM", "en-GD", "en-KN", "en-LC", "en-VC", "en-IE", "en-GY", "en-AE" };
|
|
if (string.Equals(split[1], "gal", StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(split[1], "gallon", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (britishCultureNames.Contains(culture.Name))
|
|
{
|
|
split[1] = "ImperialGallon";
|
|
}
|
|
else
|
|
{
|
|
split[1] = "UsGallon";
|
|
}
|
|
}
|
|
|
|
if (string.Equals(split[3], "gal", StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(split[3], "gallon", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (britishCultureNames.Contains(culture.Name))
|
|
{
|
|
split[3] = "ImperialGallon";
|
|
}
|
|
else
|
|
{
|
|
split[3] = "UsGallon";
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Choose "UsOunce" or "ImperialOunce" according to current culture when the input contains "o.z", "o.z.", "oz" or "ounce".
|
|
/// </summary>
|
|
public static void OunceHandler(ref string[] split, CultureInfo culture)
|
|
{
|
|
HashSet<string> britishCultureNames = new HashSet<string>() { "en-AI", "en-VG", "en-GB", "en-KY", "en-MS", "en-AG", "en-DM", "en-GD", "en-KN", "en-LC", "en-VC", "en-IE", "en-GY", "en-AE" };
|
|
if (string.Equals(split[1], "o.z", StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(split[1], "ounce", StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(split[1], "o.z.", StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(split[1], "oz", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (britishCultureNames.Contains(culture.Name))
|
|
{
|
|
split[1] = "ImperialOunce";
|
|
}
|
|
else
|
|
{
|
|
split[1] = "UsOunce";
|
|
}
|
|
}
|
|
|
|
if (string.Equals(split[3], "o.z", StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(split[3], "ounce", StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(split[3], "o.z.", StringComparison.OrdinalIgnoreCase) ||
|
|
string.Equals(split[3], "oz", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
if (britishCultureNames.Contains(culture.Name))
|
|
{
|
|
split[3] = "ImperialOunce";
|
|
}
|
|
else
|
|
{
|
|
split[3] = "UsOunce";
|
|
}
|
|
}
|
|
}
|
|
|
|
public static ConvertModel Parse(Query query)
|
|
{
|
|
string[] split = query.Search.Split(' ');
|
|
|
|
InputInterpreter.ShorthandFeetInchHandler(ref split, CultureInfo.CurrentCulture);
|
|
InputInterpreter.InputSpaceInserter(ref split);
|
|
|
|
if (split.Length != 4)
|
|
{
|
|
// deny any other queries than:
|
|
// 10 ft in cm
|
|
// 10 ft to cm
|
|
return null;
|
|
}
|
|
|
|
InputInterpreter.DegreePrefixer(ref split);
|
|
InputInterpreter.MetreToMeter(ref split);
|
|
InputInterpreter.FeetToFt(ref split);
|
|
InputInterpreter.KPHHandler(ref split);
|
|
InputInterpreter.GallonHandler(ref split, CultureInfo.CurrentCulture);
|
|
InputInterpreter.OunceHandler(ref split, CultureInfo.CurrentCulture);
|
|
if (!double.TryParse(split[0], out double value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return new ConvertModel()
|
|
{
|
|
Value = value,
|
|
FromUnit = split[1],
|
|
ToUnit = split[3],
|
|
};
|
|
}
|
|
}
|
|
}
|