2016-04-19 8 views
2

Ich möchte einige Zahlen in Zeichenfolgen in C# mit benutzerdefinierter Gruppe/Tausendertrennzeichen und Dezimaltrennzeichen formatieren. Die Gruppe und das Dezimaltrennzeichen können basierend auf Benutzereingaben geändert werden, sodass ich ein NumberFormatInfo-Objekt anstelle einer hartcodierten Formatierungszeichenfolge verwenden möchte. Mein Code unten erhält die richtigen Trennzeichen, aber es ändert die Genauigkeit der Zahl, um immer zwei Dezimalstellen zu sein, während ich die volle Genauigkeit der Zahl behalten und nur Dezimalstellen bei Bedarf anzeigen möchte (so haben Integer-Werte keine Dezimalstellen) .Formatieren Sie die Zahl als Zeichenfolge mit benutzerdefinierter Gruppe und Dezimaltrennzeichen, ohne die Genauigkeit zu ändern.

Wie kann ich das erreichen? Ich vermute, ich muss den "N" -Parameter ändern, aber ändern, was?

double n1 = 1234; 
double n2 = 1234.5; 
double n3 = 1234567.89; 
double n4 = 1234.567; 

var nfi = new NumberFormatInfo(); 
nfi.NumberDecimalSeparator = ","; 
nfi.NumberGroupSeparator = " "; 

string s1 = n1.ToString("N", nfi); //want "1 234" but I get "1 234,00" 
string s2 = n2.ToString("N", nfi); //want "1 234,5" but I get "1 234,50" 
string s3 = n3.ToString("N", nfi); //correct output of "1 234 567,89" 
string s4 = n4.ToString("N", nfi); //want " 1 234,567" but I get "1 234,57" 

Antwort

3

Unten ist die Lösung, die ich als eine Erweiterungsmethode kam.

public static string Format(this double d, NumberFormatInfo numberFormatInfo) 
{ 
    string s = d.ToString(CultureInfo.InvariantCulture); 
    int index = s.IndexOf('.'); 
    int decimalPlaces = index == -1 ? 0 : s.Length - index - 1; 
    return d.ToString($"N{decimalPlaces}", numberFormatInfo); 
} 
+0

Haben Sie meine Lösung mit 'Replace' und' Trim' oder 'LINQ' versucht? Diese sind alle integriert, wenn Sie nach integrierten Lösungen suchen ... – Ian

+0

Ihre Lösung wird unter vielen Umständen fehlschlagen, da Sie "" ### ### ###. ### "als Parameter und diese Zeichenfolge angeben hängt vom Wert des Double und der Anzahl der Dezimalstellen ab und hängt auch vom Dezimaltrennzeichen und vom Gruppentrennzeichen im NumberFormatInfo-Objekt ab, zum Beispiel schlägt Ihre Lösung mit dem doppelten Wert von 0.1234 fehl drei Dezimalstellen.Das Erstellen einer benutzerdefinierten Version dieser Zeichenfolge für jede Zahl und NumberFormatInfo Objekt ist fehleranfällig und nicht praktisch.Meine Lösung funktioniert immer mit einem double und einem beliebigen NumberFormatInfo-Objekt – tjsmith

+0

Ich sehe ... dann können Sie auch 'LINQ' verwenden , da es eine eingebaute ist. Die 'LINQ' Lösung sollte in der Lage sein, andere Lösungen, die Sie erwähnen, zu handhaben. – Ian

0

Edit:

Es ist eine Abhilfe durch eingebaute in ToString() (Ziffer für Platzhalter mit #) undReplaceund/oderTrim:

double n1 = 1234; 
double n2 = 1234.5; 
double n3 = 1234567.89; 
double n4 = 1234.567; 
string s1 = n1.ToString("### ### ###.###").Replace(".",",").Trim(); 
string s2 = n2.ToString("### ### ###.###").Replace(".", ",").Trim(); 
string s3 = n3.ToString("### ### ###.###").Replace(".", ",").Trim(); 
string s4 = n4.ToString("### ### ###.###").Replace(".", ",").Trim(); 

Kombinieren ing es mit numerischem Format , als Dezimalzeichen nicht Arbeit allerdings zu lesen:

double n1 = 1234; 
double n2 = 1234.5; 
double n3 = 1234567.89; 
double n4 = 1234.567; 

var nfi = new NumberFormatInfo(); 
nfi.NumberDecimalSeparator = ","; 
nfi.NumberGroupSeparator = " "; 

string s1 = n1.ToString("### ### ###,###", nfi); //doesn't work 
string s2 = n2.ToString("### ### ###,###", nfi); 
string s3 = n3.ToString("### ### ###,###", nfi); 
string s4 = n4.ToString("### ### ###,###", nfi); 

Original:

Ich denke, man nicht nur die eingebaute in ToString() verwenden kann, um es zu bekommen Recht. Sie wahrscheinlich einige LINQ Tricks brauchen das gewünschte Ergebnis zu erhalten:

  1. Zuerst double ist nicht präzise:

    double n1 = 1234; 
    double n2 = 1234.5; 
    double n3 = 1234567.89; 
    double n4 = 1234.567; 
    
    var nfi = new NumberFormatInfo(); 
    nfi.NumberDecimalSeparator = ","; 
    nfi.NumberGroupSeparator = " "; 
    
    string s1 = new string(n1.ToString("N", nfi).Reverse().SkipWhile(x => x == '0' || x == ',').Reverse().ToArray()); 
    string s2 = new string(n2.ToString("N", nfi).Reverse().SkipWhile(x => x == '0' || x == ',').Reverse().ToArray()); 
    string s3 = new string(n3.ToString("N", nfi).Reverse().SkipWhile(x => x == '0' || x == ',').Reverse().ToArray()); 
    string s4 = new string(n4.ToString("N", nfi).Reverse().SkipWhile(x => x == '0' || x == ',').Reverse().ToArray()); 
    

    Es gibt Grund wegen ist die zwei Dinge, wie folgt. Bei der Eingabe etwas wie double n = 1234.5, der tatsächliche double gespeicherten Wert so etwas wie n = 1234.499999999999998 könnte

  2. Zweitens ist es etwa ToString(). Es wird nur zum Formatieren verwendet. Mit anderen Worten, hängt davon ab, wie Sie es diktieren, wird es etwas zeigen. Wenn Sie beispielsweise angeben, dass die Zahl mit zwei signifikanten Stellen nach dem Dezimaltrennzeichen angezeigt werden soll, wird die Zahl mit genau zwei signifikanten Stellen nach dem Dezimaltrennzeichen angezeigt.

Nun setzen die beiden Dinge zusammen wir ein Dilemma hier bekam! Was Sie wollen, ist das Programm: "Zeige mir so viele Ziffern wie nötig". Wenn Sie jedoch double n = 1234.5 eingeben, zeigt das Programm stattdessen 1234.499999999999998 an! Auf der anderen Seite wollen Sie die Zahl nach dem Dezimaltrennzeichen auch nicht fixieren.

Also, ich denke, Sie sollten LINQ SkipWhile und Reverse verwenden, um dies zu tun, nicht durch einfache integrierte.

Verwandte Themen