2012-01-06 70 views
9

我需要一个函数来将用户的数字输入解析为双精度。我不能做任何客户端或更改输入怎样的用武之地。字符串分数加倍

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 

我看到这个post,但它使用Python,我只是想知道是否有人知道处理这个任何花哨的C#的方法,我花时间去之前写我自己的。

+0

来改善你见过[这](http://stackoverflow.com/questions/7564906/convert-double-to-fraction-as-string-in-c-sharp)问题? – Bernard 2012-01-06 17:08:38

回答

2

这里是我最终使用:下面

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

编写一些代码可以做到这一点似乎并不困难。首先尝试删除所有空格,看看它是否是合法的号码。如果不是,找到合法的数字(例如“9 3/4”中的9,3,4并进行简单的算术运算:9 + 3/4 = 9.75

+1

如果删除所有空格,“9 3/4”将变为“93/4”。 – phoog 2012-01-06 17:13:31

+0

我知道。删除所有空格仅用于第一次尝试(试图将“9.25”解析为“9.25”)。为了解析“9 3/4”,你必须离开空间。 – 2012-01-06 17:15:24

3

BCL中没有内置任何内容做到这一点,但也有很多的现有mathematicalexpressionparsers会(尽管这可能是在上面这个具体情况)。

自己写一个,因为你已经张贴应该不难有限的使用情况。

5

我会使用正则表达式为这一个:

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

尚未测试,但我认为它应该工作。

Here's a demohere's another demo

3

我看到两节。第一个空格之前的所有内容都是整体部分。第一个空格之后的所有内容都是小数部分。在分开两个部分之后,可以从小数部分中剥离空格,在/字符上拆分该部分,并将第一部分除以第二部分(如果存在第二部分)。然后将结果添加到积分部分以找到答案。

该算法应该为您的每个样本提供正确的结果。它也可能给这些样本提供不正确的结果:“9。25/4”或“9 3/0”,所以这些都是需要注意的。其他东西包括领先的空格,是否要允许其他空格,货币符号,“9.25”(无空格)是否是有效的输入,以及如何处理非理性分数,如“1/3”,“1/10”(在二进制非理性)等

我通常不是测试驱动设计的巨大信徒(你应该先写测试,并为100%的覆盖面)静态类型的语言,但我认为单元测试在某些特定情况下具有价值,这是其中的一种情况。我会为一些常见和边缘案例进行一些测试,以确保无论结果如何,都能正确处理输入以通过测试。

0

我写了这个工作这种方法:

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

是否有用吗?

我想你也可以使用动态编译代码

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

这样做太冒险了 – Greg 2012-01-06 18:05:24

0

解决方案不会为负分工作。可以通过改变

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