String Fraction to Double

I need a function to parse a user inputs of numbers to doubles. I cannot do anything client side or change how the input comes in.

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

I saw this post, but it uses Python, I was just wondering if anybody knew any fancy C# ways of handling this before I spend time to write my own.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I would use regular expressions for this one:

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

Untested, as of yet, but I think it should work.

Here’s a demo, and here’s another demo.

Method 2

There is nothing built in the BCL that will do this, but there are plenty of existing mathematical expression parsers that will (though this may be over the top for this specific situation).

Writing one yourself, for the limited use cases you have posted shouldn’t be difficult.

Method 3

I see two sections. Everything before the first space is the integral section. Everything after the first space is the fractional section. After you separate the two sections, you can just strip spaces from the fractional section, split that section on the / character, and divide the first part by the 2nd part (if there is a 2nd part). Then add the result to the integral section to find your answer.

This algorithm should give a correct result for each of your samples. It might also give an incorrect result for samples like these: “9 .25/4” or “9 3/0”, so those are things to watch for. Other things include leading whitespace, whether you want to allow other whitespace, currency symbols, whether “9.25” (no spaces) is a valid input, and what to do with irrational fractions like “1/3”, “1/10” (irrational in binary), etc.

I’m not normally a huge believer in test driven design (that you should write the tests first and go for 100% coverage) for static-typed languages, but I do think unit tests have value in certain specific situations, and this is one of those situations. I would put together a few tests for both some common and edge cases, such that you can be sure whatever you end up with handles the inputs correctly to pass the tests.

Method 4

Here’s what I ended up using:

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

Method 5

It doesn’t look very difficult to write some code that would do this. First try removing all spaces and see if it’s a legal number. If it’s not, find the legal numbers (such as 9, 3, 4 in “9 3/4” and do a simple arithmetic operation: 9 + 3 / 4 = 9.75

Method 6

I wrote this method for this work:

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

Method 7

Is it useful to you ?

I think you can also use the dynamically compiling code

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

Method 8

Solution below won’t work for negative fractions. Can be improved by changing

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


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x