2014-04-23 74 views
5

我正在從舊的MFC GUI遷移到C#。用逗號將字符串轉換爲double和int是不同的。爲什麼?

我在構建基於窗體的GUI時,遇到意外的異常,將字符串轉換爲整數類型。我認爲它會像轉換字符串一樣工作。

string str = "1,000"; 
double dthou = Convert.ToDouble(str); // OK 
int ithou = Convert.ToInt32(str);  // raises an exception 

轉換爲double會給出正確的值:1000.0。 對於int轉換,我能夠得到一個解決方案:Convert.ToInt32() a string with Commas

但我很好奇,如果有任何理由背後。 或者我錯過了什麼?

我能找到一個類似的,但不完全是一個重複的問題:學習有關的文化問題後 Number parsing weirdness

[編輯]。

我處於一種文化衝擊之中,因爲到目前爲止,在韓國,浮點數和整數都用「,」表示爲數千個組和「。」。爲小數點(至少在現實世界中,在韓國,我的意思是,我認爲...)。 我想我將不得不接受MS Visual Studio的當前設置並繼續。

[EDIT2]沉睡在這個問題之後。

我認爲它更多的格式化字符串處理不一致。 ToDouble接受帶有千位分隔符的字符串(在我的文化中,逗號),但ToInt32不。如果ToDoublefloat | allowThousands,那麼爲什麼不能ToInt32已被integer | allowThousands正是我所要求的。

+8

您目前的文化是什麼? –

+1

這似乎是一個文化問題。 – Flater

+0

CultureInfo.CurrentCulture.Name告訴我「ko-KR」 – Keugyeol

回答

3

對於雙轉換,有兩種可能性:

  1. 在你的文化,,是數字組分隔符。轉換成功並返回值爲1000
  2. 或者,在您的文化中,,用作小數點分隔符。再次轉換爲浮點成功,但這次返回1

對於轉換爲整數,"1,000"根本不是一個整數。鑑於你的命名,我的懷疑是,是你的一個數字組分隔符。而且你期望它可以通過ToInt32()這樣處理。但ToInt32()不接受號碼組分隔符。 ToInt32()的有效字符是09,可選的符號前綴-+以及前導或尾隨空格。

+0

用我的文化「ko-KR」意思是韓語,轉換爲double可以給出正確的值,在這種情況下爲1000.0; – Keugyeol

+1

這取決於你的意思是正確的。例如,在法國,正確答案是'1.0'。 –

+0

我編輯了評論以添加我的文化:「ko-KR」,謝謝。 – Keugyeol

0

在英文文化中,小數點是「。」。 。在瑞典文化中,小數嘆息是「,」。無數的符號可以是「」,「」或「。」。所以這就是爲什麼當C#在小數點符號與指定區域不同時引發異常。

+0

據我所知,逗號在韓國的浮動和整數表達式中都是一樣的,當其中一個轉換拋出異常時,我意外地被捕獲了。 – Keugyeol

2

在你的個人主頁上,它說你來自韓國。這就是爲什麼我假設你現在的文化是ko-KR。 (和你said以及。)

而且它的NumberDecimalSeparator.但它的NumberGroupSeparator,

enter image description here

Convert.ToDouble作品和它假定你,是成千上萬的分隔符,而不是小數分隔符。這就是爲什麼你的dthou將是1000而不是1

Convert.ToInt32(string)明確使用Int32.Parse(string, CultureInfo.CurrentCulture)並且這種方法implemented like;

public static int Parse(String s, IFormatProvider provider) 
{ 
    return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); 
} 

正如您所見,此方法使用NumberStyles.Integer作爲默認值。這就是爲什麼你的字符串可以成功解析,只有它包含其中之一;

  • 開頭的空白
  • 結尾的空白
  • 領先的符號(正或負)

而且,由於你的字符串有數以千計的分隔符或小數點分隔符(這取決於哪一個時使用的)這個方法拋出異常。

取而代之的是,你可以用它Int32.Parse(String, NumberStyles, IFormatProvider) overload可以指定你的NumberStylesNumberStyles.AllowDecimalPointNumberStyles.AllowThousands

作爲一個例子;

string str = "1,000"; 
int ithou = Int32.Parse(str, NumberStyles.AllowThousands, 
         new CultureInfo("ko-KR")); 
Console.WriteLine(ithou); // Prints 1000 

如果你想獲得1結果,你可以使用CultureInfo.Clone method到你的文化,並設置它的NumberDecimalSeparatorNumberGroupSeparator性能喜歡;

string str = "1,000"; 
CultureInfo c = (CultureInfo)CultureInfo.GetCultureInfo("ko-KR").Clone(); 
c.NumberFormat.NumberDecimalSeparator = ","; 
c.NumberFormat.NumberGroupSeparator = "."; 
int dthou = Int32.Parse(str, NumberStyles.AllowDecimalPoint, c); 
Console.WriteLine(dthou); // Prints 1 

我不認爲這是一個文化問題。這是格式化字符串的不一致處理 。 ToDouble用逗號接受字符串,但 ToInt32不。這就像回到原來的問題, ,但不能ToInt32接受逗號,就像 ToDouble函數?

哦,我親愛的朋友,你還在想錯了..

一切都在你的情況下,一個文化問題。沒有這樣的事情「Convert.ToDouble()接受逗號字符串,但Convert.ToInt32()」。

讓我們再來看看這些方法是如何實現的。

Convert.ToDouble(string)明確使用Double.Parse(value, CultureInfo.CurrentCulture)並且它是implemented like;

public static double Parse(String s, IFormatProvider provider) 
{ 
    return Parse(s, NumberStyles.Float| NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider)); 
} 

有了這個NumberStyles.Float| NumberStyles.AllowThousands,你可以在你的代碼中使用兩個小數點或千位分隔符,但,是你的文化的NumberGroupSeparator沒有NumberDecimalSeparator。這就是爲什麼你的字符串將被解析爲千位分隔符。 沒有這樣的事情Convert.ToDouble使用逗號的字符串。它可以使用您當前的文化的NumberDecimalSeparatorNumberGroupSeparator取決於您的字符串具有哪個字符。如果兩者相等,NumberDecimalSeparator將佔主導地位並將被使用。

Convert.ToInt32(string)明確使用Int32.Parse(string, CultureInfo.CurrentCulture)並且它是implemented like;

public static int Parse(String s, IFormatProvider provider) 
{ 
    return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); 
} 

正如我之前所說,NumberStyles.Integer允許你的字符串有三樣東西;領先的白色空間,尾隨的白色空間和領先的積極或消極的跡象。無論是逗號還是點號,您的字符串都有小數點分隔符或千位分隔符不能解析。

但不能ToInt32被實現爲接受逗號,就像 ToDouble函數?

我以前告訴過你。 Convert.ToInt32沒有過載需要NumberStyles作爲參數。您可以使用Int32.Parse(String, NumberStyles, IFormatProvider) overload,您可以指定NumberStyles枚舉來解析您的小數點分隔符或千位分隔符。

+0

感謝您的詳細描述。知道了ToInt32()的內部工作之後,我想知道它是否可以是NumberStyles.AllowThousands,而不是ParseInt32函數參數中的NumberStyles.Integer。 – Keugyeol

+1

@ Keegyeol更新了我的答案。看一眼。如果你在不改變文化的情況下使用了'NumberStyles.AllowThousands',它將被解析爲千位分隔符,結果將爲'1000'。如果您想克隆自己的文化並將其設置爲NumberDecimalSeparator和NumberGroupSeparator,那麼您可以通過枚舉NumberStyles.AllowDecimalPoint來獲得結果1。 –

+0

@Downvoter至少要留心評論,以便我可以看到我可能會出錯的地方? –