แยกวิเคราะห์ตัวเลขจากสัญกรณ์เอกซ์โพเนนเชียล


88

ฉันต้องการแยกวิเคราะห์สตริง "1.2345E-02" (ตัวเลขที่แสดงในสัญกรณ์เอกซ์โพเนนเชียล) เป็นประเภทข้อมูลทศนิยม แต่Decimal.Parse("1.2345E-02")เพียงแค่แสดงข้อผิดพลาด

คำตอบ:


175

มันเป็นเลขทศนิยมคุณต้องบอกมันว่า:

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

50

ใช้งานได้หากคุณระบุNumberStyles.Float:

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

ฉันไม่แน่ใจว่าทำไมจึงไม่รองรับโดยค่าเริ่มต้นค่าเริ่มต้นคือการใช้NumberStyles.Numberซึ่งใช้รูปแบบ AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint และ AllowTh thousands อาจเกี่ยวข้องกับประสิทธิภาพ การระบุเลขชี้กำลังค่อนข้างหายากฉันคิดว่า


ฉันพยายามทำให้สิ่งนี้ทำงานร่วมกับ double แต่ดูเหมือนว่าจะไม่เป็นเช่นนั้น ไม่แน่ใจว่าทำไมถึงทำไม่ได้ .. ?
Jant

@JanT: ไม่มีข้อมูลมากไปกว่า "มันจะไม่" และ "มันไม่ได้" ฉันไม่สามารถช่วยอะไรได้มากกว่านี้ ฉันขอแนะนำให้คุณถามคำถามใหม่ที่มีรายละเอียดมากขึ้นแสดงสิ่งที่คุณพยายามและสิ่งที่เกิดขึ้น
Jon Skeet

ฉันพยายามเรียกใช้โค้ดเหมือนในคำตอบของคุณ แต่แทนที่จะใช้ทศนิยมสองครั้ง แต่พบวิธีแก้ปัญหาแล้ว ไชโย
Jant

1
@JanT คงจะดีถ้าคุณสามารถแบ่งปันวิธีแก้ปัญหาของคุณได้ ฉันมีปัญหาเดียวกันและสามารถใช้ข้อมูลได้ ขอบคุณ!
Rick Glimmer

@RickGlimmer: ฉันไม่แน่ใจว่าคุณรู้ได้อย่างไรว่าปัญหาของคุณเหมือนกับของ JanT เนื่องจากพวกเขาไม่เคยให้รายละเอียดเกี่ยวกับสิ่งที่พวกเขาพยายามทำ การแทนที่decimalด้วยdoubleในรหัสของฉันทำงานได้ดีสำหรับฉันเช่นเดียวกับที่ฉันคาดหวังไว้ หากคุณสามารถให้รายละเอียดเกี่ยวกับสิ่งที่คุณกำลังพยายามรหัสที่คุณใช้และผลลัพธ์ก็จะช่วยได้ง่ายกว่ามาก
Jon Skeet

35

นอกเหนือจากการระบุ NumberStyles แล้วฉันขอแนะนำให้คุณใช้ฟังก์ชันdecimal.TryParseเช่น:

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

เป็นอีกทางเลือกหนึ่งของ NumberStyles คุณสามารถใช้ชุดเฉพาะได้หากคุณต้องการรูปแบบของคุณ เช่น:

NumberStyles.AllowExponent | NumberStyles.Float

1
แต่ไม่จำเป็นต้องใช้ Float กับ AllowExponent เนื่องจาก Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowDecimalPoint | AllowExponent
Lukáš Kmoch

@ LukášKmochคุณพูดถูก ไม่รวมพลังแห่งความเคยชินเช่นเดียวกับคนอื่น ๆ (นอกเหนือจากใด ๆ ) ไม่ควรเจ็บที่จะดำเนินการพิเศษหรือแม้ว่า
Sverrir Sigmundarson


9

ระมัดระวังเกี่ยวกับคำตอบที่เลือก: มีความละเอียดอ่อนที่ระบุSystem.Globalization.NumberStyles ลอยในรูปทศนิยมซึ่งอาจนำไปสู่System.FormatExceptionเนื่องจากระบบของคุณอาจรอตัวเลขที่จัดรูปแบบด้วย ',' แทนที่จะเป็น ''

ตัวอย่างเช่นในรูปแบบภาษาฝรั่งเศส "1.2345E-02" ไม่ถูกต้องคุณต้องแปลงเป็น "1,2345E-02" ก่อน

โดยสรุปให้ใช้บางสิ่งตามแนวของ:

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

1
คุณพูดถูกจริงๆ ฉันไม่เข้าใจว่าทำไมไม่มีใครนำมันขึ้นมา
Carles Alcolea

10
ใช้ CultureInfo.InvariantCulture เป็นพารามิเตอร์ที่ 3 ของ Parse
Andriy Kozachuk ได้ดีขึ้นเมื่อ

4

ฉันพบว่าNumberStyles.Floatในบางกรณีการส่งผ่านจะเปลี่ยนกฎที่ใช้ประมวลผลสตริงและผลลัพธ์ในผลลัพธ์ที่แตกต่างจากNumberStyles.Number(กฎเริ่มต้นที่ใช้โดยdecimal.Parse)

ตัวอย่างเช่นรหัสต่อไปนี้จะสร้างFormatExceptionในเครื่องของฉัน:

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

ฉันขอแนะนำให้ใช้อินพุตNumberStyles.Number | NumberStyles.AllowExponentเนื่องจากจะอนุญาตให้ใช้เลขเอกซ์โพเนนเชียลและจะยังคงประมวลผลสตริงภายใต้decimalกฎ

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

ในการตอบคำถามของผู้โพสต์คำตอบที่ถูกต้องควรเป็น:

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

1

คำเตือนเกี่ยวกับการใช้ NumberStyles ใด ๆ :

"6.33E + 03" แปลงเป็น 6330 ตามที่คาดไว้ ในภาษาเยอรมันจุดทศนิยมจะแสดงด้วยลูกน้ำ แต่ 6,33E + 03 จะแปลงเป็น 633000! นี่เป็นปัญหาสำหรับลูกค้าของฉันเนื่องจากไม่ทราบวัฒนธรรมที่สร้างข้อมูลและอาจแตกต่างจากวัฒนธรรมที่ดำเนินการกับข้อมูล ในกรณีของฉันฉันมีสัญกรณ์ทางวิทยาศาสตร์เสมอดังนั้นฉันจึงสามารถแทนที่ลูกน้ำเป็นจุดทศนิยมได้เสมอก่อนที่จะแยกวิเคราะห์ แต่ถ้าคุณกำลังทำงานกับตัวเลขตามอำเภอใจเช่นตัวเลขที่จัดรูปแบบสวย ๆ เช่น 1,234,567 วิธีนั้นก็ไม่ได้ผล


0

คุณไม่จำเป็นต้องแทนที่จุด (ตามลำดับลูกน้ำ) เพียงระบุอินพุต IFormatProvider:

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

หากคุณต้องการตรวจสอบและแปลงค่าเลขชี้กำลังให้ใช้สิ่งนี้

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);
}

หวังว่านี่จะช่วยใครบางคนได้


0

เริ่มต้นNumberStyleสำหรับการdecimal.Parse(String)มีดังนั้นถ้าคุณเพียงต้องการที่จะเพิ่มฟังก์ชันการทำงานเพื่อให้เลขชี้กำลังแล้วคุณสามารถทำบิตหรือจะรวมถึงNumberStyles.NumberNumberStyles.AllowExponent

decimal d = decimal
    .Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.