Cách tốt nhất để hiển thị số thập phân mà không có số 0 ở cuối


107

Có trình định dạng hiển thị nào sẽ xuất ra các số thập phân như các biểu diễn chuỗi này trong c # mà không làm tròn bất kỳ không?

// decimal -> string

20 -> 20
20.00 -> 20
20.5 -> 20.5
20.5000 -> 20.5
20.125 -> 20.125
20.12500 -> 20.125
0.000 -> 0

{0. #} Sẽ làm tròn và việc sử dụng một số hàm kiểu Trim sẽ không hoạt động với cột số bị ràng buộc trong lưới.

Câu trả lời:


147

Bạn có số vị trí thập phân tối đa mà bạn cần hiển thị không? (Các ví dụ của bạn có tối đa là 5).

Nếu vậy, tôi nghĩ rằng định dạng bằng "0. #####" sẽ làm được những gì bạn muốn.

    static void Main(string[] args)
    {
        var dList = new decimal[] { 20, 20.00m, 20.5m, 20.5000m, 20.125m, 20.12500m, 0.000m };

        foreach (var d in dList)
            Console.WriteLine(d.ToString("0.#####"));
    }

4
Và bạn luôn có thể ném một số ký hiệu # cắt cổ * vào định dạng. * không khoa học
Anthony Pegram

3
+1 - ngẫu nhiên, bạn không cần # đứng đầu. "0. #####" hoạt động giống nhau. Và theo cách nào đó, điều này sẽ làm tròn từ 0 (chỉ FYI).
TrueWill

14
@TrueWill Trên thực tế, nó tạo ra sự khác biệt. d == 0,1m thì "0. #" hiển thị "0,1" và "#. #" hiển thị ".1" mà không có số 0. Không sai hay đúng, chỉ phụ thuộc vào những gì bạn muốn.
AaronLS

4
Tôi luôn cần hiển thị một vị trí thập phân, vì vậy tôi đã sử dụng chuỗi định dạng "0.0#".
Mã với Hammer vào

1
Xem câu trả lời của Erwin Mayer dưới đây.
shlgug

32

Tôi vừa học được cách sử dụng mã Gđịnh dạng đúng cách . Xem Tài liệu MSDN . Có một lưu ý nhỏ nói rằng các số không ở cuối sẽ được giữ nguyên cho các loại thập phân khi không có độ chính xác được chỉ định. Tại sao họ làm điều này tôi không biết, nhưng chỉ định số chữ số tối đa cho độ chính xác của chúng tôi sẽ khắc phục được vấn đề đó. Vì vậy, để định dạng số thập phân, G29là cách tốt nhất.

decimal test = 20.5000m;
test.ToString("G"); // outputs 20.5000 like the documentation says it should
test.ToString("G29"); // outputs 20.5 which is exactly what we want

21
Điều này sẽ dẫn đến 0,00001 được hiển thị dưới dạng 1E-05
xem ngày

17

Định dạng chuỗi này sẽ tạo nên ngày của bạn: "0. ###############################". Hãy nhớ rằng số thập phân có thể có nhiều nhất 29 chữ số có nghĩa.

Ví dụ:

? (1000000.00000000000050000000000m).ToString("0.#############################")
-> 1000000.0000000000005

? (1000000.00000000000050000000001m).ToString("0.#############################")
-> 1000000.0000000000005

? (1000000.0000000000005000000001m).ToString("0.#############################")
-> 1000000.0000000000005000000001

? (9223372036854775807.0000000001m).ToString("0.#############################")
-> 9223372036854775807

? (9223372036854775807.000000001m).ToString("0.#############################")
-> 9223372036854775807.000000001

4
Đây là câu trả lời chung nhất cho vấn đề. Không chắc tại sao đây không phải là định dạng "G" mặc định cho số thập phân. Các số không ở cuối không thêm thông tin. Tài liệu của Microsoft có một cảnh báo kỳ lạ đối với số thập phân: docs.microsoft.com/en-us/dotnet/standard/base-types/… Tuy nhiên, nếu số là Số thập phân và thông số chính xác bị bỏ qua, ký hiệu điểm cố định luôn được sử dụng và các số không ở cuối được giữ nguyên.
Eric Roller

10

Đây là một biến thể khác của những gì tôi đã thấy ở trên. Trong trường hợp của tôi, tôi cần giữ nguyên tất cả các chữ số có nghĩa ở bên phải dấu thập phân, nghĩa là bỏ tất cả các số 0 sau chữ số có nghĩa nhất. Chỉ nghĩ rằng nó sẽ được tốt đẹp để chia sẻ. Mặc dù vậy, tôi không thể đảm bảo về hiệu quả của việc này, nhưng khi cố gắng đạt được tính thẩm mỹ, bạn đã bị thiệt hại khá nhiều bởi sự kém hiệu quả.

public static string ToTrimmedString(this decimal target)
{
    string strValue = target.ToString(); //Get the stock string

    //If there is a decimal point present
    if (strValue.Contains("."))
    {
        //Remove all trailing zeros
        strValue = strValue.TrimEnd('0');

        //If all we are left with is a decimal point
        if (strValue.EndsWith(".")) //then remove it
            strValue = strValue.TrimEnd('.');
    }

    return strValue;
}

Chỉ có vậy thôi mà đã muốn ném vào hai xu của mình.


3
Đây dễ dàng là giải pháp tốt nhất, nó cũng không tăng lên với giá "0,0". Tôi đã thêm một cờ mặc định để làm cho các số nguyên tùy chọn hiển thị là "1.0" và điều này vừa làm cho tất cả các số thập phân của tôi trở thành dòng. Không thể hiểu tại sao đây không phải là câu trả lời tốt nhất, + rất nhiều.
Steve Hibbert

2
Điều này đặc biệt tốt nếu ai đó đã chuyển cho bạn một chuỗi. Bạn chỉ có thể thay đổi nó thành ToTrimmedString (chuỗi strValue này) và xóa dòng đầu tiên.
PRMan

Đó là một điểm hay. Tôi nghĩ rằng khi tôi viết bài này, tôi đang xử lý các giá trị đã là số thập phân hoặc thứ gì đó nên tôi muốn bao hàm toàn bộ. Thay vào đó, bạn có thể có phần thân của phương thức đó bên trong một phương thức được nạp chồng khác mà thay vào đó, nó chấp nhận một chuỗi.
dyslexicanaboko

Đó là một giải pháp tốt khi bạn có thể gọi ToTrimmedString () nhưng có nhiều trường hợp bạn bị giới hạn ở một chuỗi định dạng.
Mike Marynowski

1
Trong khi dấu phân tách thập phân phải là văn hóa cụ thể, tôi nghĩ đây là một giải pháp tốt. Một câu hỏi nhỏ, tại sao không chỉ strValue.TrimEnd('0').TrimEnd('.')thay vì EndsWithséc?
nawfal

5

Một giải pháp khác, dựa trên câu trả lời của chứng khó đọc , nhưng không phụ thuộc vào văn hóa hiện tại:

public static string ToTrimmedString(this decimal num)
{
    string str = num.ToString();
    string decimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    if (str.Contains(decimalSeparator))
    {
        str = str.TrimEnd('0');
        if(str.EndsWith(decimalSeparator))
        {
            str = str.RemoveFromEnd(1);
        }
    }
    return str;
}

public static string RemoveFromEnd(this string str, int characterCount)
{
    return str.Remove(str.Length - characterCount, characterCount);
}

Tuyệt quá. Ngoại trừ SqlDecimal, nó là CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator bất chấp cài đặt vùng.
user2091150

4

Phương thức mở rộng:

public static class Extensions
{
    public static string TrimDouble(this string temp)
    {
        var value = temp.IndexOf('.') == -1 ? temp : temp.TrimEnd('.', '0');
        return value == string.Empty ? "0" : value;
    }
}

Mã ví dụ:

double[] dvalues = {20, 20.00, 20.5, 20.5000, 20.125, 20.125000, 0.000};
foreach (var value in dvalues)
    Console.WriteLine(string.Format("{0} --> {1}", value, value.ToString().TrimDouble()));

Console.WriteLine("==================");

string[] svalues = {"20", "20.00", "20.5", "20.5000", "20.125", "20.125000", "0.000"};
foreach (var value in svalues)
    Console.WriteLine(string.Format("{0} --> {1}", value, value.TrimDouble()));

Đầu ra:

20 --> 20
20 --> 20
20,5 --> 20,5
20,5 --> 20,5
20,125 --> 20,125
20,125 --> 20,125
0 --> 0
==================
20 --> 20
20.00 --> 2
20.5 --> 20.5
20.5000 --> 20.5
20.125 --> 20.125
20.125000 --> 20.125
0.000 --> 0

1
"20.00 -> 2" Tôi nghĩ đó là hành vi không tốt. Để khắc phục, hãy gọi TrimEnd hai lần: TrimEnd ('0'); TrimEnd (',');
Vadim

2
KHÔNG SỬ DỤNG mã đã viết ở trên. @VadymK đúng là hành vi của nó bị lỗi. Nó sẽ cắt bỏ các số không ở phía trước dấu chấm nếu không có dấu chấm.
Sevin7

2
Câu trả lời trên stackoverflow không dành cho sao chép-dán. Chúng được sử dụng như một nguồn học tập . Mã sampel này dạy bạn sử dụng IndexOfđể tìm các ký tự trong một chuỗi. Khá dễ dàng để điều chỉnh ví dụ để giải quyết vấn đề không có số thập phân.
jgauffin

2

Tôi không nghĩ điều đó có thể xảy ra nhưng một phương pháp đơn giản như thế này sẽ làm được

public static string TrimDecimal(decimal value)
{
    string result = value.ToString(System.Globalization.CultureInfo.InvariantCulture);
    if (result.IndexOf('.') == -1)
        return result;

    return result.TrimEnd('0', '.');
}

2

Nó khá dễ dàng để thực hiện ngay lập tức:

Decimal YourValue; //just as example   
String YourString = YourValue.ToString().TrimEnd('0','.');

điều đó sẽ xóa tất cả các số không ở cuối khỏi Số thập phân của bạn.

Điều duy nhất bạn cần làm là thêm .ToString().TrimEnd('0','.');vào một biến số thập phân để chuyển đổi a Decimalthành một Stringsố không ở cuối, như trong ví dụ trên.

Ở một số vùng, nó phải là một .ToString().TrimEnd('0',',');(nơi họ sử dụng dấu phẩy thay vì một điểm, nhưng bạn cũng có thể thêm dấu chấm và dấu phẩy làm tham số để chắc chắn).

(bạn cũng có thể thêm cả hai làm tham số)


Bạn có thể không nhận ra điều này, nhưng khi xử lý một paramsđối số, bạn không cần phải xây dựng một mảng một cách rõ ràng. Vì vậy, thay vì dài dòng, TrimEnd("0".ToCharArray())bạn chỉ có thể viết TrimEnd('0')(lưu ý: chuyển qua đơn charthay vì a char[]).
Dan Tao

@Dan Tao: Cảm ơn, tôi quên điều đó. Đã lâu rồi tôi không sử dụng C #. Mặc dù cả hai phiên bản đều hoạt động, nhưng tôi đã chỉnh sửa bài đăng của mình.
Mervin

@Mervin: Bạn cần chuyển a char, không phải a string(nên: dấu nháy đơn, không phải dấu nháy kép). Tôi đã sửa nó cho bạn - hy vọng bạn không phiền.
Dan Tao

1
Giải pháp của bạn sẽ tạo ra đầu ra như "2." khi nó chỉ có số không.
jgauffin

2
Sau đó, tôi sẽ đề nghị gọi .ToString (). TrimEnd ('0'). TrimEnd ('.'). Cũng thay vì '.' tốt hơn hết là có CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator để nó hoạt động trên các nền văn hóa.
Ε Г И І И О

1
decimal val = 0.000000000100m;
string result = val == 0 ? "0" : val.ToString().TrimEnd('0').TrimEnd('.');

0

Tôi đã kết thúc với mã sau:

    public static string DropTrailingZeros(string test)
    {
        if (test.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
        {
            test = test.TrimEnd('0');
        }

        if (test.EndsWith(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
        {
            test = test.Substring(0,
                test.Length - CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator.Length);
        }

        return test;
    }

0

Tôi đã kết thúc với biến thể này:

public static string Decimal2StringCompact(decimal value, int maxDigits)
    {
        if (maxDigits < 0) maxDigits = 0;
        else if (maxDigits > 28) maxDigits = 28;
        return Math.Round(value, maxDigits, MidpointRounding.ToEven).ToString("0.############################", CultureInfo.InvariantCulture);
    }

Ưu điểm:

bạn có thể chỉ định số lượng chữ số có nghĩa tối đa sau điểm để hiển thị trong thời gian chạy;

bạn có thể chỉ định rõ ràng một phương thức vòng;

bạn có thể kiểm soát một cách rõ ràng một nền văn hóa.


0

Bạn có thể tạo phương thức mở rộng

public static class ExtensionMethod {
  public static decimal simplify_decimal(this decimal value) => decimal.Parse($"{this:0.############}");
}

0

Tôi đã thực hiện các phương pháp mở rộng dưới đây cho bản thân để phù hợp với một trong các dự án của mình, nhưng có thể chúng sẽ có lợi cho người khác.

using System.Numerics;
using System.Text.RegularExpressions;
internal static class ExtensionMethod
{
    internal static string TrimDecimal(this BigInteger obj) => obj.ToString().TrimDecimal();
    internal static string TrimDecimal(this decimal obj) => new BigInteger(obj).ToString().TrimDecimal();
    internal static string TrimDecimal(this double obj) => new BigInteger(obj).ToString().TrimDecimal();
    internal static string TrimDecimal(this float obj) => new BigInteger(obj).ToString().TrimDecimal();
    internal static string TrimDecimal(this string obj)
    {
        if (string.IsNullOrWhiteSpace(obj) || !Regex.IsMatch(obj, @"^(\d+([.]\d*)?|[.]\d*)$")) return string.Empty;
        Regex regex = new Regex("^[0]*(?<pre>([0-9]+)?)(?<post>([.][0-9]*)?)$");
        MatchEvaluator matchEvaluator = m => string.Concat(m.Groups["pre"].Length > 0 ? m.Groups["pre"].Value : "0", m.Groups["post"].Value.TrimEnd(new[] { '.', '0' }));
        return regex.Replace(obj, matchEvaluator);
    }
}

Mặc dù nó sẽ yêu cầu tham chiếu đến System.Numerics.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.