2014-04-23 7 views
5

Sto migrando da una vecchia interfaccia grafica MFC a C#.Convertire una stringa con le virgole da raddoppiare e int sono diverse. Perché?

Stavo costruendo una GUI basata su form quando li ho un'eccezione imprevista la conversione di una stringa in un tipo intero. Supponevo che avrebbe funzionato allo stesso modo della conversione da stringa a doppia.

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

conversione di raddoppiare dà valore corretto: 1000.0. Per la conversione int, sono stato in grado di ottenere una soluzione: Convert.ToInt32() a string with Commas.

Ma io sono curioso di sapere se ci fosse alcuna ragione alla base di questo. O mi sto perdendo qualcosa?

sono stato in grado di trovare una simile, ma non esattamente una domanda duplicato: Number parsing weirdness

[EDIT] dopo aver appreso in merito alla questione della cultura.

sono in una sorta di cultura-shock perché fino ad ora, in Corea, entrambi numeri numero punto mobile e ad interi sono espressi con "" per il gruppo migliaia e "" per punto decimale (almeno nel mondo reale, in Corea, voglio dire, penso ...). Suppongo che dovrò accettare le impostazioni correnti di MS Visual Studio e continuare.

[EDIT2] dopo aver dormito su questo problema.

penso che sia più del trattamento incoerente della stringa formattata. ToDouble accetta stringhe con separatore di migliaia (nella mia cultura, virgola), ma ToInt32 non lo fa. Se ToDouble è float | allowThousands, allora perché ToInt32 non è stato integer | allowThousands è quello che sto chiedendo.

+8

Qual è la tua cultura attuale? –

+1

Questo sembra un problema di cultura. – Flater

+0

CultureInfo.CurrentCulture.Name mi dice "ko-KR" – Keugyeol

risposta

3

Per la doppia conversione, ci sono due possibilità:

  1. Nella vostra cultura, , è il separatore di gruppo numero. E così la conversione ha successo e restituisce un valore di 1000.
  2. In alternativa, nella propria cultura, , viene utilizzato come separatore decimale. Ancora una volta la conversione in virgola mobile ha successo ma questa volta restituisce 1.

Per la conversione in numero intero, "1,000" non è semplicemente un numero intero. Il mio sospetto, dato il tuo nome, è che , è un separatore di gruppi di numeri per te. E ti aspetti che venga trattato in questo modo dal ToInt32(). Ma ToInt32() non accetta i separatori dei gruppi di numeri. I caratteri validi per ToInt32() sono 0-9, il segno del prefisso opzionale - o + e spazi iniziali o finali.

+0

Con la mia cultura "ko-KR" che significa coreano, la conversione in raddoppia dà il valore corretto, in questo caso, 1000.0; – Keugyeol

+1

Dipende da cosa intendi per corretto. In Francia, ad esempio, la risposta corretta è '1.0'. –

+0

Ho modificato il commento per aggiungere la mia cultura: "ko-KR", grazie. – Keugyeol

0

Nella cultura inglese il segno decimale è "." . Nella cultura svedese il sospiro decimale è ",". La miriade di segni può essere "", "," o ".". Ecco perché C# genera un'eccezione quando il segno decimale è diverso dalla sua cultura specificata.

+0

Per quanto ne so, la virgola viene utilizzata allo stesso modo per entrambe le espressioni floating e integer in Corea, e mi è stato inaspettatamente catturato quando uno della conversione ha generato un'eccezione. – Keugyeol

2

Nel tuo profilo, si dice che vieni dalla Corea del Sud. Ecco perché presumo che la tua cultura attuale sia ko-KR. (E tu pure said.)

Ed è NumberDecimalSeparator è . ma è NumberGroupSeparator è ,

enter image description here

vostri Convert.ToDouble opere ed assume il vostro , è un separatore migliaia, non separatore decimale. Ecco perché il tuo dthou sarà 1000 non 1.

Convert.ToInt32(string) utilizza Int32.Parse(string, CultureInfo.CurrentCulture) esplicitamente e questo metodo implemented come;

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

Come si può vedere questo metodo utilizza NumberStyles.Integer come predefinito. Ed è per questo che la tua stringa può essere analizzata correttamente solo contando uno di questi;

  • spazi bianchi
  • Trailing spazio bianco
  • Leading segno (positivo o negativo)

E dal momento che la stringa ha separatore delle migliaia o separatore decimale (questo dipende da quale quello utilizzato per) questo metodo genera un'eccezione.

Invece di che, si può utilizzare Int32.Parse(String, NumberStyles, IFormatProvider) overload cui è possibile specificare il vostro NumberStyles come NumberStyles.AllowDecimalPoint o NumberStyles.AllowThousands

A titolo di esempio;

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

Se si desidera ottenere 1 di conseguenza, è possibile utilizzare CultureInfo.Clone method per la vostra cultura e impostare è NumberDecimalSeparator e NumberGroupSeparator immobili come;

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 

non credo che sia un problema culturale. È la gestione incoerente dello della stringa formattata. ToDouble accetta le stringhe con la virgola, ma non lo è per ToInt32 . È come tornare alla domanda originale di nuovo, ma non è possibile implementare ToInt32 per accettare la virgola, proprio come la funzione ToDouble ?

Oh, mio ​​caro amico, che si sta ancora pensando sbagliato ..

Tutto è un problema culturale nel tuo caso. Non esiste una cosa del genere "Convert.ToDouble() accetta stringhe con la virgola, ma Convert.ToInt32() non corrisponde a".

Guardiamo ancora una volta come questi metodi sono implementati.

Convert.ToDouble(string) utilizza Double.Parse(value, CultureInfo.CurrentCulture) esplicitamente ed è uguale a implemented;

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

Con questo NumberStyles.Float| NumberStyles.AllowThousands, è possibile utilizzare sia il punto decimale o separatore delle migliaia nel codice, ma , è di vostra cultura NumberGroupSeparator non NumberDecimalSeparator. Ecco perché la stringa verrà analizzata come un migliaio di seperetori. Non esiste una cosa del genere Convert.ToDouble utilizza una stringa con la virgola. Può essere utilizzato il NumberDecimalSeparator o NumberGroupSeparator della cultura corrente a seconda del carattere della stringa. Se entrambi fossero uguali, NumberDecimalSeparator sarà dominante e verrà utilizzato.

Convert.ToInt32(string) utilizza Int32.Parse(string, CultureInfo.CurrentCulture) esplicitamente ed è implemented simili;

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

come ho detto prima, NumberStyles.Integer permette tre cose per la stringa; condurre lo spazio bianco, trascinare lo spazio bianco e condurre un segno positivo o negativo. Non può essere analizzato se la stringa ha separatore decimale o separatore di migliaia , indipendentemente dalla virgola o dal punto.

ma non poteva essere attuato ToInt32 ad accettare il proprio come funzione ToDouble virgola?

Te l'ho già detto. Convert.ToInt32 non ha un sovraccarico richiede NumberStyles come parametro. È possibile utilizzare Int32.Parse(String, NumberStyles, IFormatProvider) overload che è possibile specificare l'enumerazione NumberStyles per l'analisi del separatore decimale o del separatore delle migliaia.

+0

Grazie per la descrizione dettagliata. Dopo aver conosciuto il funzionamento interno di ToInt32(), mi chiedo se avrebbe potuto essere NumberStyles.AllowThousands anziché NumberStyles.Integer nell'argomento della funzione ParseInt32. – Keugyeol

+1

@Keugyeol Aggiornato la mia risposta. Dare un'occhiata a. Se hai usato 'NumberStyles.AllowThousands' senza alcun cambiamento nella tua cultura, è stato analizzato come migliaia di separatori e il risultato sarà' 1000'. Se tu "correggi" la tua cultura e setti come 'NumberDecimalSeparator' e' NumberGroupSeparator' come vuoi, puoi ottenere '1' come risultato con l'enumerazione' NumberStyles.AllowDecimalPoint'. –

+0

@Downvoter cura di commentare almeno così posso vedere dove potrei sbagliarmi? –