2012-01-06 15 views
9

Ho bisogno di una funzione per analizzare un input dell'utente di numeri in doppio. Non posso fare lato client qualcosa o modificare la modalità di ingresso entra.String Fraction to Double

Input  | Desired Output 
"9"   | 9 
"9 3/4"  | 9.75 
" 9 1/ 2 " | 9.5 
"9 .25"  | 9.25 
"9,000 1/3" | 9000.33 
"1/4"  | .25 

ho visto questo post, ma utilizza Python, mi stavo solo chiedendo se qualcuno sapesse qualsiasi C# modi fantasiosi di manipolazione di questo prima di spendere il tempo di scrivi il mio

+0

Hai visto [questo] (http://stackoverflow.com/questions/7564906/convert-double-to-fraction-as-string-in-c-sharp) domanda ? – Bernard

risposta

2

Ecco quello che ho finito per usare:

private double ParseDoubleFromString(string num) 
{ 
    //removes multiple spces between characters, cammas, and leading/trailing whitespace 
    num = Regex.Replace(num.Replace(",", ""), @"\s+", " ").Trim(); 
    double d = 0; 
    int whole = 0; 
    double numerator; 
    double denominator; 

    //is there a fraction? 
    if (num.Contains("/")) 
    { 
     //is there a space? 
     if (num.Contains(" ")) 
     { 
      //seperate the integer and fraction 
      int firstspace = num.IndexOf(" "); 
      string fraction = num.Substring(firstspace, num.Length - firstspace); 
      //set the integer 
      whole = int.Parse(num.Substring(0, firstspace)); 
      //set the numerator and denominator 
      numerator = double.Parse(fraction.Split("/".ToCharArray())[0]); 
      denominator = double.Parse(fraction.Split("/".ToCharArray())[1]); 
     } 
     else 
     { 
      //set the numerator and denominator 
      numerator = double.Parse(num.Split("/".ToCharArray())[0]); 
      denominator = double.Parse(num.Split("/".ToCharArray())[1]); 
     } 

     //is it a valid fraction? 
     if (denominator != 0) 
     { 
      d = whole + (numerator/denominator); 
     } 
    } 
    else 
    { 
     //parse the whole thing 
     d = double.Parse(num.Replace(" ", "")); 
    } 

    return d; 
} 
1

Non sembra molto difficile scrivere un codice che faccia questo. Prima prova a rimuovere tutti gli spazi e vedere se è un numero legale. Se non lo è, trova i numeri legali (come 9, 3, 4 in "9 3/4" e fai una semplice operazione aritmetica: 9 + 3/4 = 9.75

+1

Se si rimuovono tutti gli spazi, "9 3/4" diventa "93/4". – phoog

+0

Lo so. La rimozione di tutti gli spazi è solo per il primo tentativo (cercando di analizzare "9.25" come "9.25"). Per analizzare "9 3/4" devi lasciare gli spazi. –

3

Non c'è niente di costruito nel BCL che fare questo, ma ci sono un sacco di esistere mathematicalexpressionparsers che sarà (se questo può essere sopra le righe per questa situazione specifica).

scriverne uno da soli, per i casi di utilizzo limitati che hai postato non dovrebbe essere difficile.

5

vorrei usare le espressioni regolari per questo uno:

Regex re = new Regex(@"^\s*(\d+)(\s*\.(\d*)|\s+(\d+)\s*/\s*(\d+))?\s*$"); 
string str = " 9 1/ 2 "; 
Match m = re.Match(str); 
double val = m.Groups[1].Success ? double.Parse(m.Groups[1].Value) : 0.0; 

if(m.Groups[3].Success) { 
    val += double.Parse("0." + m.Groups[3].Value); 
} else { 
    val += double.Parse(m.Groups[4].Value)/double.Parse(m.Groups[5].Value); 
} 

Non ancora testato, ma credo che dovrebbe funzionare.

Here's a demo e here's another demo.

3

Vedo due sezioni. Tutto prima del primo spazio è la sezione integrale. Tutto dopo il primo spazio è la sezione frazionale. Dopo aver separato le due sezioni, puoi semplicemente rimuovere gli spazi dalla sezione frazionale, dividere quella sezione sul carattere/e dividere la prima parte dalla seconda parte (se c'è una seconda parte). Quindi aggiungi il risultato alla sezione integrale per trovare la risposta.

Questo algoritmo dovrebbe fornire un risultato corretto per ciascuno dei campioni. Potrebbe anche dare un risultato errato per campioni come questi: "9 .25/4" o "9 3/0", quindi quelli sono cose da tenere d'occhio. Altre cose includono lo spazio bianco iniziale, se si desidera consentire altri spazi bianchi, simboli di valuta, se "9.25" (senza spazi) è un input valido e cosa fare con le frazioni irrazionali come "1/3", "1/10" (irrazionale in binario), ecc.

Normalmente non sono un grande sostenitore del design guidato da test (che dovresti scrivere prima i test e ottenere una copertura del 100%) per i linguaggi tipizzati staticamente, ma penso che i test unitari avere valore in determinate situazioni specifiche, e questa è una di quelle situazioni. Vorrei mettere insieme alcuni test sia per alcuni casi comuni che per quelli marginali, in modo tale da poter essere sicuri che qualsiasi cosa finisca con gestisca correttamente gli input per superare i test.

0

Ho scritto questo metodo per questo lavoro:

private double DoWork(string data) 
    { 
     double final = 0; 

     foreach (string s in data.Split(' ')) 
     { 
      if (s.Contains('/')) 
      { 
       final += double.Parse(s.Split('/')[0])/double.Parse(s.Split('/')[1]); 
      } 
      else 
      { 
       double tryparse = 0; 
       double.TryParse(s, out tryparse); 
       final += tryparse; 
      } 
     } 

     return final; 
    } 
0

E 'utile a voi?

Penso che si può anche utilizzare il codice di compilazione in modo dinamico

static void Main(string[] args) 
    { 
     var value = "9 3/4"; 
     value = value.Split(' ')[0] + "d + " + value.Split(' ')[1] + "d"; 

     var exp = " public class DynamicComputer { public static double Eval() { return " + value + "; }}"; 

     CodeDomProvider cp = new Microsoft.CSharp.CSharpCodeProvider(); 
     ICodeCompiler icc = cp.CreateCompiler(); 
     CompilerParameters cps = new CompilerParameters(); 
     CompilerResults cres; 

     cps.GenerateInMemory = true; 

     cres = icc.CompileAssemblyFromSource(cps, exp); 

     Assembly asm = cres.CompiledAssembly; 

     Type t = asm.GetType("DynamicComputer"); 

     double d = (double)t.InvokeMember("Eval", 
      BindingFlags.InvokeMethod, 
      null, 
      null, 
      null); 

     Console.WriteLine(d); 

     Console.Read(); 
    } 
+0

questo è WAYYY troppo rischioso – Greg

0

soluzione qui di seguito non funziona per le frazioni negative.Può essere migliorata modificando

//is it a valid fraction? 
    if (denominator != 0) 
    { 
     d = whole + (numerator/denominator); 
    } 
    to 
    //is it a valid fraction? 
    if (denominator != .0) 
    { 
     var sign = Math.Sign(whole); 

     d = whole + sign*(numerator/denominator); 
    }