524 lines
18 KiB
C#
524 lines
18 KiB
C#
using System.Runtime.CompilerServices;
|
|
using YLErp.Commons;
|
|
|
|
namespace System
|
|
{
|
|
/// <summary>
|
|
/// 数字帮助类
|
|
/// </summary>
|
|
public static class NumberHelper
|
|
{
|
|
/// <summary>
|
|
/// 非四舍五入情况下截取最大小数位数字
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static double Truncate(double value, int minDecimals, int maxDecimals, bool percent)
|
|
{
|
|
var decimals = maxDecimals > minDecimals ? maxDecimals : minDecimals;
|
|
|
|
if (percent)
|
|
{
|
|
decimals += 2;
|
|
}
|
|
|
|
if (decimals > 0)
|
|
{
|
|
var pow = Math.Pow(10, decimals);
|
|
|
|
return Math.Truncate(value * pow) / pow;
|
|
}
|
|
else
|
|
{
|
|
return Math.Truncate(value);
|
|
}
|
|
}
|
|
public static decimal Truncate(decimal value, int minDecimals, int maxDecimals, bool percent)
|
|
{
|
|
var decimals = maxDecimals > minDecimals ? maxDecimals : minDecimals;
|
|
|
|
if (percent)
|
|
{
|
|
decimals += 2;
|
|
}
|
|
|
|
if (decimals > 0)
|
|
{
|
|
var pow = Math.Pow(10, decimals);
|
|
var dePow = Convert.ToDecimal(pow);
|
|
return Math.Truncate(value * dePow) / dePow;
|
|
}
|
|
else
|
|
{
|
|
return Math.Truncate(value);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 获取数字格式化字符串
|
|
/// </summary>
|
|
/// <param name="minDecimals">最小小数位</param>
|
|
/// <param name="maxDecimals">最大小数位</param>
|
|
/// <param name="percent">是否百分比格式</param>
|
|
/// <param name="grouping">是否千分位分组</param>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static string GetFormat(int minDecimals, int maxDecimals, bool percent, bool grouping)
|
|
{
|
|
var sb = StringBuilderPool.Acquire();
|
|
|
|
sb.Append(grouping ? "#,##0" : "0");
|
|
|
|
if (minDecimals > 0)
|
|
{
|
|
sb.Append('.').Append('0', minDecimals);
|
|
|
|
if (maxDecimals > minDecimals)
|
|
{
|
|
sb.Append('#', maxDecimals - minDecimals);
|
|
}
|
|
}
|
|
else if (maxDecimals > 0)
|
|
{
|
|
sb.Append('.').Append('#', maxDecimals);
|
|
}
|
|
|
|
if (percent)
|
|
{
|
|
sb.Append('%');
|
|
}
|
|
|
|
return sb.Release();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 转换为中文数字
|
|
/// </summary>
|
|
/// <param name="number">数字</param>
|
|
/// <param name="moneyStyle">金钱样式</param>
|
|
public static string ConvertToChinese(double number, bool moneyStyle)
|
|
{
|
|
return moneyStyle ? ChineseNumberConvert.MoneyCn(number) : ChineseNumberConvert.NumberCn(number);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 转换为人民币大写
|
|
/// </summary>
|
|
public static string CmycurD(double num)
|
|
{
|
|
return ChineseNumberConvert.CmycurD(num);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 小写转大写数字(整数)
|
|
/// </summary>
|
|
public static string CurrToChnInt(int n)
|
|
{
|
|
return ChineseNumberConvert.CurrToChnInt(n);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 正常化double值(NAN或无限大数字转换为0)
|
|
/// </summary>
|
|
public static double Normalize(this double value)
|
|
{
|
|
return double.IsNaN(value) || double.IsInfinity(value) ? 0 : value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 正常化double值(NAN或无限大数字转换为0)
|
|
/// </summary>
|
|
public static double Normalize(this double? value)
|
|
{
|
|
return !value.HasValue || double.IsNaN(value.Value) || double.IsInfinity(value.Value) ? 0 : value.Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查double值是否为(NAN或无限大数字)
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
public static bool IsNormalize(this double value)
|
|
{
|
|
return !(double.IsNaN(value) || double.IsInfinity(value));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查double值是否为(NULL NAN或无限大数字)
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
public static bool IsNormalize(this double? value)
|
|
{
|
|
return value.HasValue && value.Value.IsNormalize();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 浮点数格式化
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static string Format(double? d, string fmt)
|
|
{
|
|
return d.HasValue ? d.Value.ToString(fmt) : "";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 字符串转换为doulbe数字
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static double ToDouble(string str, double defaultValue = 0)
|
|
{
|
|
return double.TryParse(str, out var val) ? val : defaultValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// decimal?转换为doulbe数字
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static double ToDouble(this decimal? d, double defaultValue = 0)
|
|
{
|
|
return d.HasValue ? Convert.ToDouble(d) : defaultValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// double转换为decimal(未处理double参数是否超出了decimal.MaxValue|MinValue的范围)
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static decimal ToDecimal(this double d, decimal defaultValue = 0)
|
|
{
|
|
return double.IsNaN(d) || double.IsInfinity(d) ? defaultValue : new decimal(d);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 尝试解析百分比数字(根据传入的字符层末尾是否为%判断)
|
|
/// </summary>
|
|
public static bool TryParse(string str, out double dvalue, out bool isPercent)
|
|
{
|
|
dvalue = 0;
|
|
isPercent = false;
|
|
|
|
if (string.IsNullOrWhiteSpace(str))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
isPercent = str.EndsWith("%");
|
|
|
|
if (isPercent)
|
|
{
|
|
str = str.TrimEnd('%');
|
|
}
|
|
|
|
if (double.TryParse(str, out dvalue))
|
|
{
|
|
if (isPercent)
|
|
{
|
|
dvalue /= 100;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// doulbe取绝对值()
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static double Abs(double value)
|
|
{
|
|
return double.IsNaN(value) || double.IsInfinity(value) ? 0 : Math.Abs(value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 中文数字转换类
|
|
/// </summary>
|
|
static class ChineseNumberConvert
|
|
{
|
|
const string cPointCn = "点十百千万十百千亿十百千";
|
|
const string cNumberCn = "零一二三四五六七八九";
|
|
|
|
public static string NumberCn(string number)
|
|
{
|
|
var S = number.ToString();
|
|
if (S == "0")
|
|
{
|
|
return "" + cPointCn[0];
|
|
}
|
|
|
|
if (!S.Contains("."))
|
|
{
|
|
S += ".";
|
|
}
|
|
|
|
var P = S.IndexOf(".");
|
|
var Result = "";
|
|
|
|
for (var i = 0; i < S.Length; i++)
|
|
{
|
|
if (P == i)
|
|
{
|
|
Result = Result.Replace("零十零", "零");
|
|
Result = Result.Replace("零百零", "零");
|
|
Result = Result.Replace("零千零", "零");
|
|
Result = Result.Replace("零十", "零");
|
|
Result = Result.Replace("零百", "零");
|
|
Result = Result.Replace("零千", "零");
|
|
Result = Result.Replace("零万", "万");
|
|
Result = Result.Replace("零亿", "亿");
|
|
Result = Result.Replace("亿万", "亿");
|
|
Result = Result.Replace("零点", "点");
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
if (P > i)
|
|
{
|
|
Result += "" + cNumberCn[S[i] - '0'] + cPointCn[P - i - 1];
|
|
}
|
|
else
|
|
{
|
|
Result += "" + cNumberCn[S[i] - '0'];
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
if (Result.Substring(Result.Length - 1, 1) == "" + cPointCn[0])
|
|
{
|
|
Result = Result.Remove(Result.Length - 1); // 一点-> 一
|
|
}
|
|
|
|
if (Result[0] == cPointCn[0])
|
|
{
|
|
Result = cNumberCn[0] + Result; // 点三-> 零点三
|
|
}
|
|
|
|
if ((Result.Length > 1) && (Result[1] == cPointCn[1]) &&
|
|
(Result[0] == cNumberCn[1]))
|
|
{
|
|
Result = Result.Remove(0, 1); // 一十三-> 十三
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
public static string NumberCn(double number)
|
|
{
|
|
return NumberCn(number.ToString());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 2021年7月20日微调
|
|
/// </summary>
|
|
/// <param name="number"></param>
|
|
/// <returns></returns>
|
|
public static string MoneyCn(double number)
|
|
{
|
|
if (number == 0)
|
|
{
|
|
return "零";
|
|
}
|
|
/*
|
|
* 修改原因是因为142,547.580 使用Math.Truncate(number * 100)后
|
|
* 变为142,547.570
|
|
*/
|
|
var Result = NumberCn(Math.Truncate(number * 100 + 1e-6) / 100);
|
|
Result = Result.Replace("一", "壹");
|
|
Result = Result.Replace("二", "贰");
|
|
Result = Result.Replace("三", "叁");
|
|
Result = Result.Replace("四", "肆");
|
|
Result = Result.Replace("五", "伍");
|
|
Result = Result.Replace("六", "陆");
|
|
Result = Result.Replace("七", "柒");
|
|
Result = Result.Replace("八", "捌");
|
|
Result = Result.Replace("九", "玖");
|
|
Result = Result.Replace("九", "玖");
|
|
Result = Result.Replace("十", "拾");
|
|
Result = Result.Replace("百", "佰");
|
|
Result = Result.Replace("千", "仟");
|
|
if (Result.Contains("点"))
|
|
{
|
|
var P = Result.IndexOf("点");
|
|
if (Result.Length >= P + 3)
|
|
{
|
|
Result = Result.Insert(P + 3, "分");
|
|
}
|
|
|
|
Result = Result.Insert(P + 2, "角");
|
|
Result = Result.Replace("点", "圆");
|
|
Result = Result.Replace("角分", "角");
|
|
Result = Result.Replace("零分", "");
|
|
Result = Result.Replace("零角", "");
|
|
Result = Result.Replace("分角", "");
|
|
if (Result.Substring(0, 2) == "零圆")
|
|
{
|
|
Result = Result.Replace("零圆", "");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Result += "圆整";
|
|
}
|
|
|
|
Result = "人民币" + Result;
|
|
return Result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 转换为人民币大写
|
|
/// </summary>
|
|
public static string CmycurD(double num)
|
|
{
|
|
var str1 = "零壹贰叁肆伍陆柒捌玖"; //0-9所对应的汉字
|
|
var str2 = "万仟佰拾亿仟佰拾万仟佰拾元角分"; //数字位所对应的汉字
|
|
var str3 = ""; //从原num值中取出的值
|
|
var str4 = ""; //数字的字符串形式
|
|
var str5 = ""; //人民币大写金额形式
|
|
int i; //循环变量
|
|
int j; //num的值乘以100的字符串长度
|
|
var ch1 = ""; //数字的汉语读法
|
|
var ch2 = ""; //数字位的汉字读法
|
|
var nzero = 0; //用来计算连续的零值是几个
|
|
int temp; //从原num值中取出的值
|
|
|
|
num = double.Parse(num.ToString("0.##")); //将num取绝对值并四舍五入取2位小数
|
|
str4 = Math.Round(num * 100).ToString("F0"); //将num乘100并转换成字符串形式
|
|
j = str4.Length; //找出最高位
|
|
if (j > 15) { return "溢出"; }
|
|
str2 = str2.Substring(15 - j); //取出对应位数的str2的值。如:200.55,j为5所以str2=佰拾元角分
|
|
|
|
//循环取出每一位需要转换的值
|
|
for (i = 0; i < j; i++)
|
|
{
|
|
str3 = str4.Substring(i, 1); //取出需转换的某一位的值
|
|
temp = Convert.ToInt32(str3); //转换为数字
|
|
if (i != (j - 3) && i != (j - 7) && i != (j - 11) && i != (j - 15))
|
|
{
|
|
//当所取位数不为元、万、亿、万亿上的数字时
|
|
if (str3 == "0")
|
|
{
|
|
ch1 = "";
|
|
ch2 = "";
|
|
nzero += 1;
|
|
}
|
|
else
|
|
{
|
|
if (str3 != "0" && nzero != 0)
|
|
{
|
|
ch1 = "零" + str1.Substring(temp * 1, 1);
|
|
ch2 = str2.Substring(i, 1);
|
|
nzero = 0;
|
|
}
|
|
else
|
|
{
|
|
ch1 = str1.Substring(temp * 1, 1);
|
|
ch2 = str2.Substring(i, 1);
|
|
nzero = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//该位是万亿,亿,万,元位等关键位
|
|
if (str3 != "0" && nzero != 0)
|
|
{
|
|
ch1 = "零" + str1.Substring(temp * 1, 1);
|
|
ch2 = str2.Substring(i, 1);
|
|
nzero = 0;
|
|
}
|
|
else
|
|
{
|
|
if (str3 != "0" && nzero == 0)
|
|
{
|
|
ch1 = str1.Substring(temp * 1, 1);
|
|
ch2 = str2.Substring(i, 1);
|
|
nzero = 0;
|
|
}
|
|
else
|
|
{
|
|
if (str3 == "0" && nzero >= 3)
|
|
{
|
|
ch1 = "";
|
|
ch2 = "";
|
|
nzero += 1;
|
|
}
|
|
else
|
|
{
|
|
//if (j > 11)
|
|
//{
|
|
// ch1 = "";
|
|
// nzero += 1;
|
|
//}
|
|
//else
|
|
//{
|
|
ch1 = "";
|
|
ch2 = str2.Substring(i, 1);
|
|
nzero += 1;
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (i == (j - 11) || i == (j - 3))
|
|
{
|
|
//如果该位是亿位或元位,则必须写上
|
|
ch2 = str2.Substring(i, 1);
|
|
}
|
|
str5 = str5 + ch1 + ch2;
|
|
|
|
if (i == j - 1 && str3 == "0")
|
|
{
|
|
//最后一位(分)为0时,加上“整”
|
|
str5 += '整';
|
|
}
|
|
}
|
|
if (num == 0)
|
|
{
|
|
str5 = "零元整";
|
|
}
|
|
return str5;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 小写转大写数字(整数)
|
|
/// 这个从otcformathelper迁移过来,最好也调用NumberCn
|
|
/// </summary>
|
|
public static string CurrToChnInt(int n)
|
|
{
|
|
string[] c_Num1 = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
|
|
string[] c_fh = { "", "十", "百", "千", "万" };
|
|
|
|
string s = n.ToString();
|
|
string ss = "";
|
|
int j = s.Length - 1;
|
|
|
|
for (int i = 0; i <= j; i++)
|
|
{
|
|
int num = Convert.ToInt32(s.Substring(i, 1));
|
|
if (j == i)
|
|
{
|
|
if (j == 0 || num != 0)
|
|
{
|
|
ss += c_Num1[num];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (num == 1)
|
|
{
|
|
ss += c_fh[j - i];
|
|
}
|
|
else
|
|
{
|
|
ss += c_Num1[num] + c_fh[j - i];
|
|
}
|
|
}
|
|
}
|
|
return ss;
|
|
}
|
|
}
|
|
}
|
|
}
|