2013-08-29 11 views
6

Ho la seguente:dire se stringa di raddoppiare/float/int/short/byte è fuori portata

string outOfRange = "2147483648"; // +1 over int.MaxValue 

Ovviamente se avete qualcosa di diverso da un numero questo fallirà:

var defaultValue = 0; 
int.TryParse(outOfRange, out defaultValue); 

La mia domanda è, dal momento che questo è un numero, e fallirà quando si int.TryParse(), come si dice che non è riuscito perché la stringa era fuori dai limiti del contenitore in cui è memorizzata?

+1

è l'analisi su un valore maggiore capacità primo (detto 'long', o' uint' se si sa avere solo positivi) quindi controllare 'Int32.Max/MinValue' percorribile? –

+0

Suppongo che potrebbe essere una soluzione. Forse qualcosa di più generico che potrebbe funzionare con qualsiasi tipo di contenitore. – gleng

+0

Perché non usi sempre la maggiore capacità necessaria se è possibile che il tuo valore trabocchi capacità più piccole? Puoi aggiungere dettagli sul contesto? –

risposta

2

Vorrei tentare di analizzare, se non riesce, quindi tentare di analizzare un valore di capacità superiore. Se il valore di capacità più elevato supera l'analisi, allora sai che è fuori portata. Se fallisce, allora è un input negativo.

string outOfRange = "2147483648"; // +1 over int.MaxValue 
int result; 
if (!Int32.TryParse(outOfRange, out result)) 
{ 
    long rangeChecker; 
    if (Int64.TryParse(outOfRange, out rangeChecker)) 
     //out of range 
    else 
     //bad format 
} 

Purtroppo, non credo che ci sia un modo per fare questo genericamente per qualsiasi tipo; dovresti scrivere un'implementazione per tutti i tipi. Quindi, ad esempio, che cosa fare per Int64? Forse utilizzare BigInteger invece:

string outOfRange = "9223372036854775808"; // +1 over Int64.MaxValue 
long result; 
if (!Int64.TryParse(outOfRange, out result)) 
{ 
    BigInteger rangeChecker; 
    if (BigInteger.TryParse(outOfRange, out rangeChecker)) 
     //out of range 
    else 
     //bad format 
} 

EDIT: double valori in virgola mobile possono essere più divertente dal momento che per quanto ne so, non c'è "BigDecimal" e si possono rendere conto anche per i valori che si avvicinano 0 per lo estremo (non sicuro a tale proposito). Forse potresti eseguire una variazione sul controllo BigInteger ma potresti anche dover tenere conto dei punti decimali (probabilmente una semplice espressione regolare sarebbe la migliore qui per avere solo numeri, un segno negativo facoltativo e solo al massimo punto decimale).Se ci sono punti decimali, dovresti troncarli e controllare semplicemente la parte intera della stringa.

EDITx2: Ecco un piuttosto brutto implementazione per il controllo double valori troppo:

// +bajillion over Double.MaxValue 
string outOfRange = "90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.1"; 
double result; 
if (!Double.TryParse(outOfRange, out result)) 
{ 
    string bigIntegerInput = outOfRange; 

    if (!Regex.IsMatch(bigIntegerInput, @"^-?[0-9]\d*(\.\d+)?$")) 
     //bad format 

    int decimalIndex = bigIntegerInput.IndexOf('.'); 
    if (decimalIndex > -1) 
     bigIntegerInput = bigIntegerInput.Substring(0, decimalIndex); 

    BigInteger rangeChecker; 
    if (BigInteger.TryParse(bigIntegerInput, out rangeChecker)) 
     //out of range 
    else 
     //bad format 
} 

Ma onestamente, a questo punto, penso che abbiamo appena andati fuori di testa. A meno che non avere qualche vero e proprio collo di bottiglia, o l'applicazione dispone di out-of-range valori immessi spesso, si potrebbe essere meglio solo la cattura di loro il tempo dispari succede come in this answer o forse più semplicemente, l'applicazione di un regex a l'input. Nel mio ultimo esempio, potrei anche aver appena smesso dopo aver fatto la regex lo stesso (ma non lo so in cima alla mia testa se le implementazioni TryParse sono più clemente, consentendo la notazione esponenziale/scientifica. dovrebbe coprire anche questi)

0

La via diretta sarebbe invece utilizzare Int32.Parse(string s) e prendere OverflowException;

OverflowException
s rappresenta un numero inferiore MinValue o maggiore di MaxValue.

+1

Le eccezioni non sono buone per il flusso di controllo. –

+1

@ It'sNotALie. In generale li eviterei per questo tipo di operazione, ma in questo caso non è semplice scrivere un sostituto. Se coinvolgi 'IFormatProvider', ancora di più. –

1

Utilizzare il normale Parse anziché TryParse. E poi usarlo all'interno di un try/catch perché ti darà l'eccezione appropriata. Vedi questo per dettagli: http://msdn.microsoft.com/en-us/library/b3h1hf19.aspx. L'eccezione che stai cercando è OverflowException.

+0

Perché utilizzare le eccezioni per il flusso di controllo quando si può semplicemente utilizzare il valore restituito di 'TryParse'? –

+1

'TryParse' restituisce un' bool' e questo non è paragonabile a ottenere molte eccezioni diverse da 'Parse'. – meilke

2
string outOfRange = "2147483648"; // +1 over int.MaxValue 
int value; 
if(! int.TryParse(outOfRange, out value)) { 
    try { 
     int.Parse(defaultValue); 
    } catch(OverflowException e) { 
     // was overflow 
    } catch(Exception e) { 
     // was other reason 
    } 
} 

Supponendo che ci sono pochi casi in cui il numero è troppo grande, il sovraccarico di un'eccezione lancio e la cattura può essere tollerabile, come i casi normali vengono gestiti con il metodo più veloce TryParse senza coinvolgere eccezioni.

Questo potrebbe funzionare simile per gli altri tipi di dati numerici come galleggianti, ...

+0

Non utilizzare eccezioni per il flusso di controllo. –

+0

Si potrebbe invece usare 'Int64.TryParse'; se passa lo sai che è fuori portata. Se fallisce, allora sai che è un input negativo. –

+0

@ChrisSinclair Ma la domanda originale voleva conoscere anche una soluzione per long, double, ecc. – FrankPl

1

vorrei guardare utilizzando System.Convert.ToInt32(String) come meccanismo per convertire le cose; Ovvero perché OverflowException è già stato implementato per te.

Questo è conveniente perché si può fare qualcosa di semplice come

try 
{ 
     result = Convert.ToInt32(value); 
     Console.WriteLine("Converted the {0} value '{1}' to the {2} value {3}.", 
        value.GetType().Name, value, result.GetType().Name, result); 
} 
catch (OverflowException) 
{ 
     Console.WriteLine("{0} is outside the range of the Int32 type.", value); 
} 
catch (FormatException) 
{ 
     Console.WriteLine("The {0} value '{1}' is not in a recognizable format.", 
        value.GetType().Name, value); 
} 

e la logica è già una parte della libreria di sistema standard.

+0

Questo indirizzo non è double/float. – hatchet

+0

Convert.ToDouble (String) e Convert.ToFloat (String) sicuramente lo fanno. E sono già implementati da MSDN. –

+0

Stavo interpretando il tuo "come meccanismo per convertire le cose" nel senso che il codice sopra potrebbe essere usato per convertire anche i doppi e i float. Se il tuo codice è un esempio che risolve parzialmente il problema, con un altro codice come quello necessario per i casi come double/float, il mio commento sopra non si applica. – hatchet

2

Si potrebbe provare l'analisi con BigInteger.

BigInteger bigInt; 
bool isAnOutOfRangeInt = BigInteger.TryParse(input, out bigInt) 
         && (bigInt > int.MaxValue || bigInt < int.MinValue); 
// if you care to have the value as an int: 
if (!isAnOutOfRangeInt) 
{ 
    int intValue = (int)bigInt; 
} 
+0

E come lo useresti per 'double's invece di' int's, come richiesto dal post originale? – FrankPl

+0

'Decimale' invece? – Matthew

4

Vorrei andare con la soluzione Try/Catch per questo scenario.

 string outOfRange = "2147483648"; 
     try 
     { 
      int.Parse(outOfRange); 
     } 
     catch (OverflowException oex) 
     { 

     } 
     catch (Exception ex) 
     { } 

So che la maggior parte delle persone qui consiglierei di evitare questo, ma a volte non ci resta che usarlo (o che non c'è bisogno di ma sarebbe solo noi risparmiare un sacco di tempo).
here's un post sull'efficienza di Try/Catch.

3

può analizzare in decimale e quindi controllare gamma, evita try/catch

string s = "2147483648"; 
decimal.Parse(s) > int.MaxValue;