Фракция строки в удвоение - PullRequest
9 голосов
/ 06 января 2012

Мне нужна функция для разбора пользовательского ввода чисел до двойных. Я не могу ничего сделать на стороне клиента или изменить способ ввода.

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

Я видел этот пост , но он использует Python, мне было просто интересно, знает ли кто-нибудь какой-нибудь причудливый способ C # справиться с этим, прежде чем я потрачу время на написание своего собственного.

Ответы [ 8 ]

5 голосов
/ 06 января 2012

Я бы использовал для этого регулярные выражения:

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

Пока не проверено, но я думаю, что это должно работать.

Вот демо , а вот еще демо .

3 голосов
/ 06 января 2012

Я вижу два раздела. Все перед первым пробелом является неотъемлемой частью. Все после первого пробела является дробным сечением. После разделения двух разделов можно просто удалить пробелы из дробного раздела, разделить этот раздел на символ / и разделить первую часть на 2-ю часть (если есть 2-я часть). Затем добавьте результат в интегральный раздел, чтобы найти свой ответ.

Этот алгоритм должен давать правильный результат для каждого из ваших образцов. Это может также дать неверный результат для сэмплов, подобных этим: «9 .25 / 4» или «9 3/0», так что это вещи, которые нужно отслеживать. Другие вещи включают начальные пробелы, хотите ли вы разрешить другие пробелы, символы валюты, является ли «9,25» (без пробелов) допустимым вводом, и что делать с иррациональными дробями, такими как «1/3», «1/10» ( иррациональное в двоичном) и т. д.

Обычно я не большой сторонник разработки с использованием тестов (что вы должны сначала написать тесты и обеспечить 100% охват) для языков со статической типизацией, но я думаю, что юнит-тесты имеют значение в определенных конкретных ситуациях, и это одна из тех ситуаций. Я бы собрал несколько тестов как для некоторых общих, так и для крайних случаев, чтобы вы могли быть уверены, что все, что у вас получится, правильно обрабатывает входные данные для прохождения тестов.

3 голосов
/ 06 января 2012

В BCL нет ничего, что могло бы сделать это, но есть множество существующих математических выражений парсеров , которые будут (хотя это может быть более верх для этой конкретной ситуации).

Написание одного самостоятельно, для случаев ограниченного использования, которые вы опубликовали, не должно быть трудным.

2 голосов
/ 06 января 2012

Вот что я в итоге использовал:

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 голос
/ 06 января 2012

Нет ничего сложного в написании кода, который бы делал это.Сначала попробуйте удалить все пробелы и посмотреть, если это законный номер.Если это не так, найдите допустимые числа (например, 9, 3, 4 в «9 3/4») и выполните простую арифметическую операцию: 9 + 3/4 = 9,75

0 голосов
/ 08 декабря 2013

Решение ниже не будет работать для отрицательных фракций.Можно улучшить, изменив

    //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);
    }
0 голосов
/ 06 января 2012

Вам это полезно?

Я думаю, вы также можете использовать динамически компилируемый код

    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 голосов
/ 06 января 2012

Я написал этот метод для этой работы:

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;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...