2013-09-02 6 views
5

Tatsächlich habe ich mehrere Systeme, die numerische Daten generieren können, und sie sind auf einigen Webservern in Textdateien gespeichert. Einige Systeme verwenden den Dezimalpunkt als Trennzeichen für Trennzeichen. Einige Systeme verwenden Dezimalzeichen als das gleiche Trennzeichen.Überregionales Dezimal-/Doppelparsing

Anwendungen (Fat Client, .net 2.0) können auch auf beiden Arten von Systemen ausgeführt werden.

Nach einiger Stolper ich dies tat: (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)); 
    } 

Würden Sie eine bessere, elegantere Art und Weise?

EDIT:

Es tut mir leid für die, bevor es nicht zu erwähnen, und da Ihre Antworten mager in dieser Richtung - ich nicht speichern kann, mit den Zahlen Kultur zu erzeugen, kann ich nur versuchen, zu ‚erkennen‘ es.

+0

Mit 'CultureInfo'? – Leri

+0

Können Sie die generierende Kultur mit dem Zahlenstring speichern? Dies würde jegliche Notwendigkeit für ein solches Fadenbiegen verringern. – SWeko

+0

Wissen Sie ungefähr, wie die generierten Zahlen sein werden? zB bis zu einer Reihe von Optionen? Ich bin mir nicht sicher, wie Ihr System mit "1000.12" umgehen würde (eigentlich weiß ich, es würde brechen). Wenn Sie nur eine begrenzte Anzahl von möglichen Formaten haben, können Sie sie einfach ausprobieren, wenn sie keine Ambiguität haben. – Chris

Antwort

0

Wenn Sie die Aufruf-Site nicht ändern können, und Sie garantieren, dass keine andere Art von Trennzeichen neben dem Dezimaltrennzeichen vorhanden sein wird, können Sie mehr oder weniger Ihre Methode verwenden. Ich würde

  1. schlage die HasDecimalComma und HasDecimalPeriod an dem Körper des Verfahrens Мoving - globaler Zustand ist absolut nicht notwendig, in diesem Fall.
  2. Verwenden Sie TryParse anstelle von Parse, weil die Zahlen voraussichtlich fehlerhaft sind.
  3. Explizit Angabe der InvariantCulture Kultur (es hat eine Dezimalzahl).
  4. Zulassen von Zahlen, die weder Komma noch Periode haben, da "3" immerhin eine Gleitkommazahl ist.

So etwas in diese Richtung:

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

(alte Antwort, im Prinzip gut, in der Praxis unmöglich)

Ich würde vorschlagen, die erzeugende Kultur entlang der Zeichenfolge zu speichern und dann verwenden Sie es, um die Methode aufzurufen, in diesen Zeilen (mit 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

Änderte die Antwort in Anbetracht dessen. – SWeko

2

Versuchen mit diesem:

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

Dies funktioniert möglicherweise nicht, wenn '.' als Tausendertrennzeichen verwendet wird. – Chris

+1

Offenbar kein Problem, wie in den Kommentaren (auf die Frage) geklärt wurde, so sieht das gut aus. – Chris

0

Gerade die aktuelle Kultur verwenden und korrekte Zahlenformat-Flags. Natürlich müssen Sie es gegen alle Kulturen testen, die möglicherweise in Ihrer Datenbank gespeichert sind. Besser: Zahlen in CultureInfo.Invariant-Kultur konvertieren, bevor sie in der Datenbank gespeichert werden. Oder: Speichern Sie auch die Kulturkennung, wenn Sie die Nummer speichern.

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

Es sei denn, einige Ihrer Kunden verwendet Persisch (fa, fa-IR-Tag) als ihre Kultur, ich glaube, Sie zu gehen gut sind:

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