mirror of
https://github.com/chylex/Query.git
synced 2025-04-29 11:34:06 +02:00
113 lines
3.1 KiB
C#
113 lines
3.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
|
|
namespace AppConv.General;
|
|
|
|
abstract class DecimalUnitConverterBase<T> : IUnitType where T : struct {
|
|
internal sealed class DecimalFuncMap : Dictionary<T, Func<decimal, decimal>> {
|
|
public DecimalFuncMap() {}
|
|
public DecimalFuncMap(int capacity) : base(capacity) {}
|
|
}
|
|
|
|
internal sealed class NameMap : Dictionary<string, T> {
|
|
public NameMap() {}
|
|
public NameMap(int capacity) : base(capacity) {}
|
|
}
|
|
|
|
protected abstract NameMap Names { get; }
|
|
protected abstract DecimalFuncMap ConvertTo { get; }
|
|
protected abstract DecimalFuncMap ConvertFrom { get; }
|
|
|
|
protected virtual int Precision => 0;
|
|
|
|
protected virtual bool CaseCheck => false;
|
|
|
|
protected virtual NumberStyles NumberStyle => NumberStyles.Float & ~NumberStyles.AllowLeadingSign;
|
|
|
|
protected virtual string ProcessSrc(string src) {
|
|
return src;
|
|
}
|
|
|
|
protected virtual string ProcessDst(string dst) {
|
|
return dst;
|
|
}
|
|
|
|
protected abstract bool IsValueInvalid(T value);
|
|
|
|
protected virtual decimal Convert(decimal value, T from, T to) {
|
|
return ConvertFrom[to](ConvertTo[from](value));
|
|
}
|
|
|
|
protected virtual string Format(decimal value) {
|
|
if (Precision > 0) {
|
|
decimal truncated = decimal.Truncate(value);
|
|
|
|
if (value == truncated) {
|
|
return truncated.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
}
|
|
|
|
int decimalPlaces = Precision;
|
|
|
|
if (Math.Abs(value) < 1M) {
|
|
double fractionalPart = (double) Math.Abs(value % 1M);
|
|
int fractionalZeroCount = -(int) Math.Ceiling(Math.Log(fractionalPart, 10D));
|
|
|
|
decimalPlaces = Math.Min(28, fractionalZeroCount + Precision);
|
|
}
|
|
|
|
string result = decimal.Round(value, decimalPlaces, MidpointRounding.ToEven).ToString(CultureInfo.InvariantCulture);
|
|
|
|
if (decimalPlaces > 0) {
|
|
result = result.TrimEnd('0').TrimEnd('.');
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public bool TryProcess(string src, string dst, out string result) {
|
|
src = ProcessSrc(src);
|
|
dst = ProcessDst(dst);
|
|
|
|
var pairs = new KeyValuePair<string, T>[2];
|
|
|
|
for (int index = 0; index < 2; index++) {
|
|
string str = index == 0 ? src : dst;
|
|
|
|
if (CaseCheck) {
|
|
List<KeyValuePair<string, T>> list = Names.Where(kvp => str.EndsWith(kvp.Key, StringComparison.InvariantCultureIgnoreCase) && (str.Length == kvp.Key.Length || !char.IsLetter(str[str.Length - kvp.Key.Length - 1]))).ToList();
|
|
|
|
if (list.Count == 1) {
|
|
pairs[index] = list[0];
|
|
}
|
|
else {
|
|
pairs[index] = list.FirstOrDefault(kvp => str.EndsWith(kvp.Key, StringComparison.InvariantCulture));
|
|
}
|
|
}
|
|
else {
|
|
pairs[index] = Names.FirstOrDefault(kvp => str.EndsWith(kvp.Key, StringComparison.InvariantCultureIgnoreCase) && (str.Length == kvp.Key.Length || !char.IsLetter(str[str.Length - kvp.Key.Length - 1])));
|
|
}
|
|
|
|
if (IsValueInvalid(pairs[index].Value)) {
|
|
result = string.Empty;
|
|
return false;
|
|
}
|
|
|
|
if (index == 0) {
|
|
src = src[..^pairs[index].Key.Length].TrimEnd();
|
|
}
|
|
}
|
|
|
|
if (decimal.TryParse(src, NumberStyle, CultureInfo.InvariantCulture, out decimal value)) {
|
|
result = Format(Convert(value, pairs[0].Value, pairs[1].Value));
|
|
return true;
|
|
}
|
|
else {
|
|
result = string.Empty;
|
|
return false;
|
|
}
|
|
}
|
|
}
|