Phân tích cú pháp một số từ Ký hiệu mũ


85

Tôi cần phân tích cú pháp chuỗi "1.2345E-02" (một số được biểu thị bằng ký hiệu hàm mũ) thành kiểu dữ liệu thập phân, nhưng Decimal.Parse("1.2345E-02")chỉ cần tạo ra một lỗi

Câu trả lời:


169

Nó là một số dấu phẩy động, bạn phải nói với nó rằng:

decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);

49

Nó hoạt động nếu bạn chỉ định NumberStyles.Float:

decimal x = decimal.Parse("1.2345E-02", NumberStyles.Float);
Console.WriteLine(x); // Prints 0.012345

Tôi không hoàn toàn chắc chắn tại sao điều này không được hỗ trợ theo mặc định - mặc định là sử dụng NumberStyles.Number, sử dụng các kiểu AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint và AllowThollionss. Có thể nó liên quan đến hiệu suất; Tôi cho rằng việc chỉ định một số mũ là tương đối hiếm.


Tôi đang cố gắng làm cho điều này hoạt động với double nhưng có vẻ như nó sẽ không. Không chắc tại sao nó không thể ..?
'19

@JanT: Không có thêm thông tin nào ngoài "nó sẽ không" và "nó không thể", tôi thực sự không thể giúp được gì nhiều hơn. Tôi khuyên bạn nên đặt một câu hỏi mới với nhiều chi tiết hơn, cho thấy những gì bạn đã thử và chính xác những gì đã xảy ra.
Jon Skeet

Tôi đã cố gắng chạy mã như trong câu trả lời của bạn nhưng thay vì số thập phân được sử dụng kép. Nhưng đã tìm thấy cách giải quyết. Chúc mừng
'19

1
@JanT Sẽ rất tuyệt nếu bạn có thể chia sẻ cách giải quyết của mình. Tôi có chính xác cùng một vấn đề và có thể sử dụng thông tin. Cảm ơn!
Rick Glimmer,

@RickGlimmer: Tôi không chắc làm thế nào bạn biết được vấn đề của bạn giống hệt như của JanT, vì họ chưa bao giờ cung cấp chi tiết về những gì họ đang cố gắng thực hiện. Thay thế decimalbằng doubletrong mã của tôi hoạt động tốt đối với tôi, giống như tôi mong đợi. Nếu bạn có thể cung cấp chi tiết về những gì bạn đang cố gắng, mã bạn đang sử dụng và kết quả, thì việc trợ giúp sẽ dễ dàng hơn nhiều.
Jon Skeet

34

Ngoài việc chỉ định NumberStyles, tôi khuyên bạn nên sử dụng hàm decimal.TryParse chẳng hạn như:

decimal result;
if( !decimal.TryParse("1.2345E-02", NumberStyles.Any, CultureInfo.InvariantCulture, out result) )
{
     // do something in case it fails?
}

Để thay thế cho NumberStyles, bạn có thể sử dụng một tập hợp cụ thể nếu bạn chắc chắn về các định dạng của mình. ví dụ:

NumberStyles.AllowExponent | NumberStyles.Float

1
Nhưng không cần thiết phải sử dụng Float với AllowExponent vì Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowDecimalPoint | AllowExponent
Lukáš Kmoch

@ LukášKmoch Quả thực bạn nói đúng. Lực lượng của thói quen như những người khác (ngoài Bất kỳ) không bao gồm nó. Tuy nhiên, không nên thực hiện thêm OR.
Sverrir Sigmundarson,

13
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);

8

Hãy thận trọng với câu trả lời đã chọn: có một tiện ích con chỉ định System.Globalization.NumberStyles.Float ở dạng Decimal.Parse có thể dẫn đến System.FormatException vì hệ thống của bạn có thể đang chờ một số được định dạng bằng ',' thay vì '.'

Ví dụ: trong ký hiệu tiếng Pháp, "1.2345E-02" không hợp lệ, trước tiên bạn phải chuyển đổi nó thành "1.2345E-02".

Tóm lại, hãy sử dụng một cái gì đó dọc theo các dòng:

Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);

1
Bạn hoàn toàn đúng. Tôi không hiểu tại sao không ai khác đưa nó lên.
Carles Alcolea

10
Sử dụng CultureInfo.InvariantCulture tốt hơn như một tham số thứ 3 của Parse
Andriy Kozachuk

3

Tôi thấy rằng việc chuyển vào NumberStyles.Float, trong một số trường hợp, thay đổi các quy tắc mà chuỗi được xử lý và dẫn đến kết quả đầu ra khác với NumberStyles.Number(các quy tắc mặc định được sử dụng bởi decimal.Parse).

Ví dụ: mã sau sẽ tạo FormatExceptiontrong máy của tôi:

CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5", NumberStyles.Float, culture); // FormatException thrown here

Tôi khuyên bạn nên sử dụng đầu vào NumberStyles.Number | NumberStyles.AllowExponent, vì điều này sẽ cho phép số mũ và sẽ vẫn xử lý chuỗi theo các decimalquy tắc.

CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5",NumberStyles.Number | NumberStyles.AllowExponent, culture); // Does not generate a FormatException

Để trả lời câu hỏi của người đăng, câu trả lời đúng thay vào đó là:

decimal x = decimal.Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
Console.WriteLine(x);

1

Cảnh báo về việc sử dụng NumberStyles.Any:

"6.33E + 03" chuyển đổi thành 6330 như mong đợi. Trong tiếng Đức, dấu thập phân được biểu thị bằng dấu phẩy, nhưng 6,33E + 03 chuyển thành 633000! Đây là một vấn đề đối với khách hàng của tôi, vì văn hóa tạo ra dữ liệu không được biết đến và có thể khác với văn hóa đang hoạt động trên dữ liệu. Trong trường hợp của tôi, tôi luôn có ký hiệu khoa học, vì vậy tôi luôn có thể thay thế dấu phẩy thành dấu thập phân trước khi phân tích cú pháp, nhưng nếu bạn đang làm việc với các số tùy ý, như các số có định dạng đẹp như 1.234.567 thì cách tiếp cận đó không hoạt động.


0

Bạn không cần thay thế các dấu chấm (tương ứng là dấu phẩy) chỉ cần chỉ định IFormatProvider đầu vào:

float d = Single.Parse("1.27315", System.Globalization.NumberStyles.Float, new CultureInfo("en-US"));
float d = Single.Parse("1,27315", System.Globalization.NumberStyles.Float, new CultureInfo("de-DE"));

0

Nếu bạn muốn kiểm tra và chuyển đổi giá trị lũy thừa, hãy sử dụng

string val = "1.2345E-02";
double dummy;
bool hasExponential = (val.Contains("E") || val.Contains("e")) && double.TryParse(val, out dummy);
if (hasExponential)
{
    decimal d = decimal.Parse(val, NumberStyles.Float);
}

Hy vọng điều này sẽ giúp ai đó.

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.