2013-09-02 4 views
5

In effetti, dispongo di più sistemi in grado di generare dati numerici e sono memorizzati su alcuni server Web in file di testo. Alcuni dei sistemi usano il punto decimale come separatore di frazioni, alcuni dei sistemi usano come virgola decimale.Decimale incrociato/doppio parsing

Le applicazioni (fat client, .net 2.0) possono essere eseguite anche su entrambi i tipi di sistemi.

Così, dopo qualche inciampo ho fatto questo: (http://pastebin.com/vhLXABDD)

public static bool HasDecimalComma; 
    public static bool HasDecimalPeriod; 

    public static double GetNumber(string NumberString) 
    { 
     if (!HasDecimalComma && !HasDecimalPeriod) 
     { 
      string s = string.Format("{0:0.0}", 123.123); 
      if (s.Contains('.')) 
      { 
       HasDecimalPeriod = true; 
      } 
      else if (s.Contains(',')) 
      { 
       HasDecimalComma = true; 
      } 
      else 
      { 
       throw new SystemException(string.Format("strange number format '{0}'", s)); 
      } 
     } 
     if (HasDecimalComma) 
     { 
      return double.Parse(NumberString.Replace('.', ',')); 
     } 
     if (HasDecimalPeriod) 
     { 
      return double.Parse(NumberString.Replace(',', '.')); 
     } 
     throw new ArgumentException(string.Format("can't parse '{0}'", NumberString)); 
    } 

suggerirebbe un modo migliore, più elegante?

EDIT:

Mi dispiace per non menzionare prima, e dal momento che le risposte magre in quella direzione - non riesco a memorizzare generare cultura con i numeri, posso solo cercare di 'rilevare' esso.

+0

Usando 'CultureInfo'? – Leri

+0

È possibile memorizzare la cultura di generazione con la stringa numerica? Ciò allevierebbe qualsiasi necessità di tale piegamento delle corde. – SWeko

+0

Sai approssimativamente quali saranno i numeri generati? ad esempio fino ad un insieme di opzioni? Non sono sicuro di come il tuo sistema si occuperebbe di analizzare "1,000.12" (in realtà so che si romperà). Se disponi di un numero limitato di formati possibili, puoi provare ognuno di essi se non hanno possibilità di ambiguità. – Chris

risposta

0

Se non è possibile modificare il sito di chiamata e si garantisce che nessun altro tipo di separatore sarà presente accanto al separatore decimale, è possibile utilizzare più o meno il metodo. Vorrei suggerire

  1. Мoving il HasDecimalComma e HasDecimalPeriod al corpo del metodo - stato globale non è assolutamente necessario in questo caso.
  2. Utilizzo di TryParse anziché Parse, in quanto è probabile che i numeri siano potenzialmente difettosi.
  3. Specificare esplicitamente la coltura InvariantCulture (ha un periodo decimale).
  4. Come numero che non ha né virgola né punto, poiché "3" è un numero in virgola mobile dopo tutto.

Quindi qualcosa in queste righe:

///comment the method assumptions here 
///otherwise the method might seem wrong 
public static double GetNumber(string numberString) 
{ 
    bool hasDecimalComma = numberString.Contains(','); 
    if (hasDecimalComma) 
    numberString = numberString.Replace(',', '.') 
    double result; 
    bool success = double.TryParse(numberString, 
         NumberStyles.Float, 
         CultureInfo.InvariantCulture, 
         out result); 
    if (success) 
    return result; 
    else 
    throw new ArgumentException(
          string.Format("can't parse '{0}'", numberString)); 
} 

(Old risposta, buona in linea di principio, in pratica impossibile)

Vorrei suggerire la conservazione della cultura di generazione lungo la corda, e quindi utilizzarlo per chiamare il metodo, seguendo queste linee (utilizzando double.TryParse):

public static double GetNumber(string numberString, CultureInfo culture) 
{ 
    double result; 
    bool success = double.TryParse(numberString, 
          NumberStyles.Float | NumberStyles.AllowThousands, 
          culture, 
          out result); 
    if (success) 
     return result; 
    else 
     throw new ArgumentException(
           string.Format("can't parse '{0}'", numberString)); 
} 
+0

Modificata la risposta alla luce di ciò. – SWeko

2

prova con questo:

static double GetDouble(string s) 
    { 
     double d; 

     var formatinfo = new NumberFormatInfo(); 

     formatinfo.NumberDecimalSeparator = "."; 

     if (double.TryParse(s, NumberStyles.Float, formatinfo, out d)) 
     { 
      return d; 
     } 

     formatinfo.NumberDecimalSeparator = ","; 

     if (double.TryParse(s, NumberStyles.Float, formatinfo, out d)) 
     { 
      return d; 
     } 

     throw new SystemException(string.Format("strange number format '{0}'", s)); 
    } 
+0

Questo potrebbe non funzionare nel caso in cui '.' venga utilizzato come separatore delle migliaia. – Chris

+1

Apparentemente non è un problema come è stato chiarito nei commenti (alla domanda) quindi questo sembra buono. – Chris

0

basta usare la cultura attuale e corrette bandiere formato numerico. Di conseguenza, devi testarlo contro tutte le culture che sono potenzialmente memorizzate nel tuo database. Migliore: convertire i numeri in cultura CultureInfo.Invariant prima ancora di memorizzarli nel database. Oppure: memorizzare anche l'identificatore di cultura quando si memorizza il numero.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Globalization; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      const string toTest = "1.006,30"; 

      float number; 
      if (float.TryParse(toTest, NumberStyles.AllowDecimalPoint | NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.CurrentCulture, out number)) 
       Console.WriteLine("Success: {0}", number); 
      else 
       Console.WriteLine("Failure: strange number format"); 

      Console.WriteLine("Press any key to finish"); 
      Console.ReadKey(); 
     } 
    } 
} 
0

A meno che alcuni dei vostri clienti sta usando Persiano (fa, fa-IR tag) come la loro cultura, penso che tu sei a posto:

// apparently, Persians use '/' as the decimal separator 
var slash = CultureInfo 
    .GetCultures(CultureTypes.AllCultures) 
    .Where(c => 
     c.NumberFormat.NumberDecimalSeparator != "," && 
     c.NumberFormat.NumberDecimalSeparator != ".") 
    .ToList();