C# 格式数字,如堆栈溢出(用K后缀四舍五入到千)
如何使用C#格式化这样的数字 10,5k,…类似这样的东西:C# 格式数字,如堆栈溢出(用K后缀四舍五入到千),c#,.net,number-formatting,C#,.net,Number Formatting,如何使用C#格式化这样的数字 10,5k,…类似这样的东西: string formatted; if (num >= 1000) { formatted = ((double)num / 1000.0).ToString("N1") + "k"; } else { formatted = num.ToString("N0"); } public class KiloFormatter: ICustomFormatter, IFormatProvider { pu
string formatted;
if (num >= 1000) {
formatted = ((double)num / 1000.0).ToString("N1") + "k";
} else {
formatted = num.ToString("N0");
}
public class KiloFormatter: ICustomFormatter, IFormatProvider
{
public object GetFormat(Type formatType)
{
return (formatType == typeof(ICustomFormatter)) ? this : null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (format == null || !format.Trim().StartsWith("K")) {
if (arg is IFormattable) {
return ((IFormattable)arg).ToString(format, formatProvider);
}
return arg.ToString();
}
decimal value = Convert.ToDecimal(arg);
// Here's is where you format your number
if (value > 1000) {
return (value / 1000).ToString() + "k";
}
return value.ToString();
}
}
String.Format(new KiloFormatter(), "{0:K}", 15600);
如果数字大于某个阈值,请将其除以1000,然后将其格式化为所需的小数位数
int input = 12392; // for example
if (input >= 10000)
{
double thousands = input/1000.0;
Console.WriteLine(string.Format("{0}K", thousands));
}
如下所示:(编辑:测试)
示例:
- 1=>
1
- 23=>
23
- 136=>
136
- 6968=>
6968
- 23067=>
23.1K
- 133031=>
133K
例如,
12345678
变为12.3KK
您可以这样包装CustomFormatter:
string formatted;
if (num >= 1000) {
formatted = ((double)num / 1000.0).ToString("N1") + "k";
} else {
formatted = num.ToString("N0");
}
public class KiloFormatter: ICustomFormatter, IFormatProvider
{
public object GetFormat(Type formatType)
{
return (formatType == typeof(ICustomFormatter)) ? this : null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (format == null || !format.Trim().StartsWith("K")) {
if (arg is IFormattable) {
return ((IFormattable)arg).ToString(format, formatProvider);
}
return arg.ToString();
}
decimal value = Convert.ToDecimal(arg);
// Here's is where you format your number
if (value > 1000) {
return (value / 1000).ToString() + "k";
}
return value.ToString();
}
}
String.Format(new KiloFormatter(), "{0:K}", 15600);
然后像这样使用它:
string formatted;
if (num >= 1000) {
formatted = ((double)num / 1000.0).ToString("N1") + "k";
} else {
formatted = num.ToString("N0");
}
public class KiloFormatter: ICustomFormatter, IFormatProvider
{
public object GetFormat(Type formatType)
{
return (formatType == typeof(ICustomFormatter)) ? this : null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (format == null || !format.Trim().StartsWith("K")) {
if (arg is IFormattable) {
return ((IFormattable)arg).ToString(format, formatProvider);
}
return arg.ToString();
}
decimal value = Convert.ToDecimal(arg);
// Here's is where you format your number
if (value > 1000) {
return (value / 1000).ToString() + "k";
}
return value.ToString();
}
}
String.Format(new KiloFormatter(), "{0:K}", 15600);
编辑:将CurrencyFormatter重命名为KiloFormatter以下代码的测试值为int.MaxValue 这不是最漂亮的代码,但却是最有效的。 但您可以将其用作: 123.KiloFormat(); 4332.KiloFormat(); 2332124.KiloFormat(); int.MaxValue.KiloFormat(); (int1-int2*int3).KiloFormat() 等等
public static class Extensions
{
public static string KiloFormat(this int num)
{
if (num >= 100000000)
return (num / 1000000).ToString("#,0M");
if (num >= 10000000)
return (num / 1000000).ToString("0.#") + "M";
if (num >= 100000)
return (num / 1000).ToString("#,0K");
if (num >= 10000)
return (num / 1000).ToString("0.#") + "K";
return num.ToString("#,0");
}
}
我只是写了一些来提供完整的信息
public static class SIPrefix
{
private static List<SIPrefixInfo> _SIPrefixInfoList = new
List<SIPrefixInfo>();
static SIPrefix()
{
_SIPrefixInfoList = new List<SIPrefixInfo>();
LoadSIPrefix();
}
public static List<SIPrefixInfo> SIPrefixInfoList
{
get
{
SIPrefixInfo[] siPrefixInfoList = new SIPrefixInfo[6];
_SIPrefixInfoList.CopyTo(siPrefixInfoList);
return siPrefixInfoList.ToList();
}
}
private static void LoadSIPrefix()
{
_SIPrefixInfoList.AddRange(new SIPrefixInfo[]{
new SIPrefixInfo() {Symbol = "Y", Prefix = "yotta", Example = 1000000000000000000000000.00M, ZeroLength = 24, ShortScaleName = "Septillion", LongScaleName = "Quadrillion"},
new SIPrefixInfo() {Symbol = "Z", Prefix = "zetta", Example = 1000000000000000000000M, ZeroLength = 21, ShortScaleName = "Sextillion", LongScaleName = "Trilliard"},
new SIPrefixInfo() {Symbol = "E", Prefix = "exa", Example = 1000000000000000000M, ZeroLength = 18, ShortScaleName = "Quintillion", LongScaleName = "Trillion"},
new SIPrefixInfo() {Symbol = "P", Prefix = "peta", Example = 1000000000000000M, ZeroLength = 15, ShortScaleName = "Quadrillion", LongScaleName = "Billiard"},
new SIPrefixInfo() {Symbol = "T", Prefix = "tera", Example = 1000000000000M, ZeroLength = 12, ShortScaleName = "Trillion", LongScaleName = "Billion"},
new SIPrefixInfo() {Symbol = "G", Prefix = "giga", Example = 1000000000M, ZeroLength = 9, ShortScaleName = "Billion", LongScaleName = "Milliard"},
new SIPrefixInfo() {Symbol = "M", Prefix = "mega", Example = 1000000M, ZeroLength = 6, ShortScaleName = "Million", LongScaleName = "Million"},
new SIPrefixInfo() {Symbol = "K", Prefix = "kilo", Example = 1000M, ZeroLength = 3, ShortScaleName = "Thousand", LongScaleName = "Thousand"},
new SIPrefixInfo() {Symbol = "h", Prefix = "hecto", Example = 100M, ZeroLength = 2, ShortScaleName = "Hundred", LongScaleName = "Hundred"},
new SIPrefixInfo() {Symbol = "da", Prefix = "deca", Example = 10M, ZeroLength = 1, ShortScaleName = "Ten", LongScaleName = "Ten"},
new SIPrefixInfo() {Symbol = "", Prefix = "", Example = 1M, ZeroLength = 0, ShortScaleName = "One", LongScaleName = "One"},
});
}
public static SIPrefixInfo GetInfo(long amount, int decimals)
{
return GetInfo(Convert.ToDecimal(amount), decimals);
}
public static SIPrefixInfo GetInfo(decimal amount, int decimals)
{
SIPrefixInfo siPrefixInfo = null;
decimal amountToTest = Math.Abs(amount);
var amountLength = amountToTest.ToString("0").Length;
if(amountLength < 3)
{
siPrefixInfo = _SIPrefixInfoList.Find(i => i.ZeroLength == amountLength).Clone() as SIPrefixInfo;
siPrefixInfo.AmountWithPrefix = Math.Round(amount, decimals).ToString();
return siPrefixInfo;
}
siPrefixInfo = _SIPrefixInfoList.Find(i => amountToTest > i.Example).Clone() as SIPrefixInfo;
siPrefixInfo.AmountWithPrefix = Math.Round(
amountToTest / Convert.ToDecimal(siPrefixInfo.Example), decimals).ToString()
+ siPrefixInfo.Symbol;
return siPrefixInfo;
}
}
public class SIPrefixInfo : ICloneable
{
public string Symbol { get; set; }
public decimal Example { get; set; }
public string Prefix { get; set; }
public int ZeroLength { get; set; }
public string ShortScaleName { get; set; }
public string LongScaleName { get; set; }
public string AmountWithPrefix { get; set; }
public object Clone()
{
return new SIPrefixInfo()
{
Example = this.Example,
LongScaleName = this.LongScaleName,
ShortScaleName = this.ShortScaleName,
Symbol = this.Symbol,
Prefix = this.Prefix,
ZeroLength = this.ZeroLength
};
}
}
我编写此方法是为了缩小
long
数字:
public string minifyLong(long value)
{
if (value >= 100000000000)
return (value / 1000000000).ToString("#,0") + " B";
if (value >= 10000000000)
return (value / 1000000000D).ToString("0.#") + " B";
if (value >= 100000000)
return (value / 1000000).ToString("#,0") + " M";
if (value >= 10000000)
return (value / 1000000D).ToString("0.#") + " M";
if (value >= 100000)
return (value / 1000).ToString("#,0") + " K";
if (value >= 10000)
return (value / 1000D).ToString("0.#") + " K";
return value.ToString("#,0");
}
略加修改的版本 这将返回以下值:
123 -> 123
1234 -> 1,234
12345 -> 12.35k
123456 -> 123.4k
1234567 -> 1.23M
12345678 -> 12.35M
123456789 -> 123.5M
我知道这是一条非常古老的线索,但我认为更一般的答案可能有用: 加:忽略了它应该是C#,所以这里翻译为:
//--Formats the number after scaling by factors of 1000, and appends a metric unit prefix (e.g. M for *1000000)
//--Mask, Prov are the standard ToString() parameters (after metric scaling has been performed)
//--MinPow10 (/Max) should be multipla of 3 and a usually a negative (/Positve) number or zero, if say +9 is used, all is in G or above (/below)
//--SwitchLimit usualy 1, but could be say 10 or 100 with few/zero decimals, The limit at which to switch prefix, if say 33 then 33000000->33M but 32900000->32900K
static string FormatMetricPrefix(double Input, String Mask ="F2", IFormatProvider Prov=null, int MinPow10 =-24, int MaxPow10 =24, int SwitchLimit =1) {
string Prefixes ="yzafpnμm KMGTPEZY";
int idx=9;
double tmp=Input;
if (Input!=0.0) {
if (+24<MaxPow10)MaxPow10=+24;
if (MinPow10<-24)MaxPow10=-24;
idx=(int)Math.Truncate(9.0+Math.Log(Math.Abs(Input/SwitchLimit))/Math.Log(1000.0));
if (idx<9+(MinPow10/3)) idx=9+(MinPow10/3); // below lower limit
if (9+(MaxPow10/3)<idx) idx=9+(MaxPow10/3); // Above upper limit
if (idx<=9)tmp *=Math.Pow(1000.0,9-idx);
if (9<idx) tmp /=Math.Pow(1000.0,idx-9);
}
if (Prov==null)Prov=CultureInfo.InvariantCulture;
return tmp.ToString(Mask,Prov)+Prefixes.Substring(idx-1,1).Trim();
}
static string FormatMetricPrefixF2DK(double Input){return FormatMetricPrefix(Input, Prov:CultureInfo.GetCultureInfo("da-DK"));}
static string FormatMetricPrefixF2US(double Input){return FormatMetricPrefix(Input, Prov:CultureInfo.GetCultureInfo("en-US"));}
static string FormatMetricPrefixF0DK(double Input){return FormatMetricPrefix(Input, Mask:"F0", MinPow10:0, Prov:CultureInfo.GetCultureInfo("da-DK"),SwitchLimit:100);}
static string FormatMetricPrefixF0US(double Input){return FormatMetricPrefix(Input, Mask:"F0", MinPow10:0, Prov:CultureInfo.GetCultureInfo("en-US"),SwitchLimit:100);}
static void Main(string[] args)
{
Console.WriteLine(FormatMetricPrefixF2US(1.234567890E+27));
Console.WriteLine(FormatMetricPrefixF2US(1234567890));
Console.WriteLine(FormatMetricPrefixF2US(0.01234567890));
Console.WriteLine(FormatMetricPrefixF2US(0.00000001234567890));
Console.WriteLine(FormatMetricPrefixF2US(1.234567890E-26));
Console.WriteLine(FormatMetricPrefixF0US(0.5));
Console.WriteLine(FormatMetricPrefixF0US(2));
Console.WriteLine(FormatMetricPrefixF0US(20000));
Console.WriteLine(FormatMetricPrefixF0US(87654321));
}
以及一系列测试/示例:
Select 0, dbo.FormatMetricPrefixF2US(1.234567890E+27)+'g'
union Select 1, dbo.FormatMetricPrefixF2US(1234567890)+'g'
union Select 2, dbo.FormatMetricPrefixF2US(123456789.0)+'g'
union Select 3, dbo.FormatMetricPrefixF2US(12345678.90)+'g'
union Select 4, dbo.FormatMetricPrefixF2US(1234567.890)+'g'
union Select 5, dbo.FormatMetricPrefixF2US(123456.7890)+'g'
union Select 6, dbo.FormatMetricPrefixF2US(12345.67890)+'g'
union Select 7, dbo.FormatMetricPrefixF2US(1234.567890)+'g'
union Select 8, dbo.FormatMetricPrefixF2US(123.4567890)+'g'
union Select 9, dbo.FormatMetricPrefixF2US(12.34567890)+'g'
union Select 10, dbo.FormatMetricPrefixF2US(1.234567890)+'g'
union Select 11, dbo.FormatMetricPrefixF2US(0.1234567890)+'g'
union Select 12, dbo.FormatMetricPrefixF2US(0.01234567890)+'g'
union Select 13, dbo.FormatMetricPrefixF2US(0.001234567890)+'g'
union Select 14, dbo.FormatMetricPrefixF2US(0.0001234567890)+'g'
union Select 15, dbo.FormatMetricPrefixF2US(0.00001234567890)+'g'
union Select 16, dbo.FormatMetricPrefixF2US(0.000001234567890)+'g'
union Select 17, dbo.FormatMetricPrefixF2US(0.0000001234567890)+'g'
union Select 18, dbo.FormatMetricPrefixF2US(0.00000001234567890)+'g'
union Select 19, dbo.FormatMetricPrefixF2US(1.234567890E-26)+'g'
union Select 20, dbo.FormatMetricPrefixF0US(0.5)
union Select 20, dbo.FormatMetricPrefixF0US(2)
union Select 21, dbo.FormatMetricPrefixF0US(20000)
union Select 22, dbo.FormatMetricPrefixF0US(87654321)
我有点晚了,但我想到了这个:
`private static List<Tuple<int, string>> ZeroesAndLetters = new List<Tuple<int, string>>()
{
new Tuple<int, string>(15, "Q"),
new Tuple<int, string>(12, "T"),
new Tuple<int, string>(9, "B"),
new Tuple<int, string>(6, "M"),
new Tuple<int, string>(3, "K"),
};
public static string GetPointsShortened(ulong num)
{
int zeroCount = num.ToString().Length;
for (int i = 0; i < ZeroesAndLetters.Count; i++)
if (zeroCount >= ZeroesAndLetters[i].Item1)
return (num / Math.Pow(10, ZeroesAndLetters[i].Item1)).ToString() + ZeroesAndLetters[i].Item2;
return num.ToString();
}`
`private static List ZeroesAndLetters=new List()
{
新元组(15,“Q”),
新元组(12,“T”),
新元组(9,“B”),
新元组(6,“M”),
新元组(3,“K”),
};
公共静态字符串GetPointsShortened(ulong num)
{
int zeroCount=num.ToString().Length;
for(int i=0;i=ZeroesAndLetters[i].Item1)
return(num/Math.Pow(10,ZeroesAndLetters[i].Item1)).ToString()+ZeroesAndLetters[i].Item2;
返回num.ToString();
}`
在ZeroesAndLetters列表中,只需添加所需的数字
15、12、9和。。。是零的数目,Q,T,B和。。。是缩写的名称。这是经过适当测试的解决方案,四舍五入。它保留了
有意义的字符
逗号或点后的数字,并使用CultureInfo
确定十进制分隔符
在我写这篇文章的时候,我明白了在大多数情况下不需要四舍五入。因此,如果不需要舍入,最好使用其他方法或扩展此解决方案
我试图确保精度不会被浮点运算所侵蚀,但我认为这可能会发生在真正大的数字上
另外,我相信这可以通过IFormatProvider
或.NET FW中类似的内在机制来改进
public static class ConversionUtilities {
class ConversionGroup {
public ConversionGroup(char symbol, long divider, int power) {
Symbol = symbol;
Divider = divider;
Power = power;
}
public char Symbol;
public long Divider;
public int Power;
}
private static ConversionGroup[] _conversionGroups = {
new ConversionGroup('k', 1000L, 3),
new ConversionGroup('m', 1000000L, 6),
new ConversionGroup('b', 1000000000L, 9)
};
/// <summary>
/// Converts integer value into string substituting 1 000 -> 1K, 1 000 000 -> 1M, 1 000 000 000 -> 1B
/// Rounds to meaingful chars
/// </summary>
/// <param name="value">value to convert</param>
/// <param name="meaninfulChars">round to that many characters after comma</param>
/// <param name="uppercase">when set K and M letters will be uppercase</param>
/// <returns></returns>
public static string ConvertIntToShortStringForm(long value, int meaninfulChars, bool uppercase) {
string ret = "";
long remainder = 0;
long fraction = 0;
char symbol = '\0';
int maxChars = meaninfulChars;
for (int i = _conversionGroups.Length - 1; i >= 0; i--) {
var group = _conversionGroups[i];
if (value >= group.Divider) {
if (meaninfulChars < 0) {
maxChars = 0;
}
else if (meaninfulChars > group.Power) {
maxChars = group.Power;
}
// int maxChars = Math.Clamp(meaninfulChars, 0, group.Power);
remainder = value % group.Divider;
if (remainder != 0) {
fraction = (long)Math.Round((double)remainder / (Math.Pow(10.0, (double)(group.Power - maxChars))));
if (maxChars == 0) {
if (value / group.Divider + fraction == 1000) {
if (i + 1 == _conversionGroups.Length) {
symbol = group.Symbol;
if (uppercase) {
symbol = Char.ToUpper(symbol);
}
return string.Format("{0}{1}", value / group.Divider + fraction + group.Symbol);
}
else {
symbol = _conversionGroups[i + 1].Symbol;
if (uppercase) {
symbol = Char.ToUpper(symbol);
}
return "1" + symbol;
}
} else {
ret += value / group.Divider + fraction;
}
}
else {
ret += value / group.Divider;
ret += CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
ret += fraction;
}
}
else {
ret += value / group.Divider;
}
symbol = group.Symbol;
if (uppercase) {
symbol = Char.ToUpper(symbol);
}
ret += symbol;
return ret;
}
}
return value.ToString();
}
}
公共静态类转换功能{
类转换组{
公共转换组(字符符号、长分隔符、整数幂){
符号=符号;
分隔器=分隔器;
功率=功率;
}
公共字符符号;
公共长分隔线;
公共权力;
}
专用静态转换组[]\u转换组={
新的转换组('k',1000L,3),
新的转换组('m',1000000ml,6),
新的转换组('b',1000000000L,9)
};
///
///将整数值转换为字符串,替换为1 000->1K,1 000->1M,1 000->1B
///一轮又一轮
///
///要转换的值
///四舍五入到逗号后的那个么多字符
///当设置K和M时,字母将为大写
///
公共静态字符串转换器IntToSortStringForm(长值、int-meaninfulChars、bool大写){
字符串ret=“”;
长余数=0;
长分数=0;
字符符号='\0';
int maxChars=平均infulchars;
对于(int i=\u conversionGroups.Length-1;i>=0;i--){
var group=_conversiongroup[i];
如果(值>=分组分隔符){
if(平均infulchars<0){
maxChars=0;
}
else if(meaninfulChars>group.Power){
maxChars=组功率;
}
//int maxChars=Math.Clamp(meaninfulChars,0,group.Power);
余数=值%group.Divider;
如果(余数!=0){
分数=(长)数学四舍五入((双)余数/(数学功率(10.0,(双)(group.Power-maxChars));
如果(maxChars==0){
if(值/分组除法器+分数==1000){
if(i+1==\u conversionGroups.Length){
symbol=组。symbol;
if(大写){
symbol=Char.ToUpper(symbol);
}
返回string.Format(“{0}{1}”,value/group.Divider+fraction+group.Symbol);
}
否则{
symbol=_转换组[i+1]。symbol;
if(大写){
symbol=Char.ToUpper(symbol);
}
返回“1”+符号;
}
}否则{
ret+=值/组。除法器+分数;
}
}
否则{
ret+=值/组分隔符;
ret+=CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
ret+=分数;
}
}
否则{
ret+=
1 -> 1
21 -> 21
321 -> 321
4,321 -> 4.32K
54,321 -> 54.3K
654,321 -> 654.3K
7,654,321 -> 7.65M
87,654,321 -> 87.6M
987,654,321 -> 987.6M
1,987,654,321 -> 1,987.6M
public static string KFormatter(long num)
{
if (num >= 1000000000) { return (num / 1000000000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "B"; }
if (num >= 1000000) { return (num / 1000000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "M"; }
if (num >= 10000) { return (num / 1000D).ToString("0.#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' }) + "K"; }
return num.ToString("0,#", CultureInfo.InvariantCulture).TrimStart(new char[] { '0' });
}