Определите количество символов, используемых double.Parse - PullRequest
0 голосов
/ 20 сентября 2018

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

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


Обновление

Я наградил Оливье Жако-Дескомба ответом, так как он обладал самым полным Regex, и избил меня ударом своим собственнымответ, как я бы использовал Regex.Единственный недостаток в этом ответе, который я вижу, - это не учет мест с запятой и точками с разными культурами (которые я учел в своем ответе, хотя это выглядит довольно грязно).

Однако реальное решение яБуду реализовывать, не буду использовать Regex.Причина, по которой я до сих пор присуждаю ответ, заключается в том, что, по сути, я задавал неправильный вопрос.Я думаю, что ответ Regex - лучшее решение для вопроса, который я задал.

Решение, которое я придумал, состоит в том, чтобы перебрать доступные единицы и сравнить со строкой, используя inputStr.EndsWith(unitStr), и когда я получаюположительное совпадение, я сразу узнаю, какова длина числа, вычитая длину строки единиц измерения из тестовой строки, а затем я могу использовать double.Parse() с тем, что осталось (после обрезки).

Ответы [ 5 ]

0 голосов
/ 21 сентября 2018

Вот решение не-Regex, которое пришло мне в голову.Если вы можете гарантировать, что ваши входные данные всегда будут в формате номер-пространство-единица измерения, то вы можете просто сделать следующее:

public static (double Value, string unit) Parse(string value)
{
    var values = value.Split(" ");

    double number;
    if (!double.TryParse(values[0], out number))
        throw new FormatException("Value cannot be parsed as a floating point number.");

    string unit = values[1];

    return (number, unit);
}

Если ваш формат входной строки не соответствует, вы можете сделать следующее:что-то похожее на это, чтобы соответствовать этому формату.

0 голосов
/ 20 сентября 2018

Простой вариант, который не включает регулярные выражения:

var input = "42,666 towels";

// Get a char[] of all numbers or separators (',' or '.', depending on language):
var numericChars = input
                    .TakeWhile(c => c == ',' || c == '.' || Char.IsNumber(c))
                    .ToArray();

// Use the chars to init a new string, which can be parsed to a number: 
var nr = Double.Parse(new String(numericChars));

// ...and the remaining part of the original string is the unit:
// (Note that we use Trim() to remove any whitespace between the number and the unit)
var unit = input.Substring(numericChars.Count()).Trim();

// Outputs: Nr is 42,666, unit is towels.
Console.WriteLine($"Nr is {nr}, unit is {unit}.");

Обновление

В ответ на комментарий ниже, вот расширение.Я признаю, что это разрушает некоторую элегантную простоту, описанную выше, но, по крайней мере, она читаема, конфигурируема (расширяема) и работает:

var nrFormat = System.Globalization.CultureInfo.CurrentCulture.NumberFormat;

// Remove or add strings to this list as needed:
var validStrings = 
    new List<string>{ 
                    nrFormat.NaNSymbol, 
                    nrFormat.NegativeSign, 
                    nrFormat.NumberDecimalSeparator, 
                    nrFormat.PercentGroupSeparator, 
                    nrFormat.PercentSymbol, 
                    nrFormat.PerMilleSymbol, 
                    nrFormat.PositiveInfinitySymbol, 
                    nrFormat.PositiveSign
                };

validStrings.AddRange(nrFormat.NativeDigits);
validStrings.Add("^");
validStrings.Add("e");
validStrings.Add("E");
validStrings.Add(" ");


// You can use more complex numbers, like: 
var input = "-42,666e-3 Towels";

// Get all numbers or separators (',' or '.', depending on language):
var numericChars = input.TakeWhile(c => validStrings.Contains("" + c)).ToArray();

// Use the chars to init a new string, which can be parsed to a number: 
var nr = Double.Parse(new String(numericChars));

// ...and the remaining part of the original string is the unit:
// (Note that we use Trim() to remove any whitespace between the number and the unit)
var unit = input.Substring(numericChars.Count()).Trim();

// Outputs is now: "Nr is -0,042666, unit is Towels"
Console.WriteLine($"Nr is {nr}, unit is {unit}.");

Как видите, ввод может быть намного более сложнымсейчас;вы даже можете использовать что-то вроде var input = "∞ Garden Gnomes";, что даст чудесный результат:

Nr равно ∞, единица измерения - садовые гномы.

0 голосов
/ 20 сентября 2018

Мое текущее решение состоит в том, чтобы использовать Regex для интерпретации значения с плавающей запятой и затем получить длину, чтобы узнать, где начинается модуль.

    public static (double Value, string unit) Parse(string value)
    {
        var result = RegexParseDouble.Match(value);
        if(result.Success)
        {
            return (double.Parse(value.Substring(result.Length)), value.Substring(result.Length));
        }
        throw new FormatException("Value cannot be parsed as a floating point number.");
    }

    private static Regex RegexParseDouble
    {
        get => new Regex(
            @"^[-+]?(\d+" +
            Thread.CurrentThread.CurrentCulture.NumberFormat.NumberGroupSeparator +
            @"\d+)*\d*(" +
            Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator +
            @")?\d+([eE][-+]?\d+)?");
    }

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

0 голосов
/ 20 сентября 2018

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

var parseNumUnit = new Regex(
 @"(?<num>(\+|-)?([0-9,]+(\.)?[0-9]*|[0-9,]*(\.)?[0-9]+)((e|E)(\+|-)?[0-9]+)?)\s*(?<unit>[a-zA-Z]*)"
);

Match match = parseNumUnit.Match("+13.234e-3m");
string number = match.Groups["num"].Value; // "+13.234e-3" 
string unit = match.Groups["unit"].Value; // "m"

Здесь

(?<name>expression)    captures the expression in a group named "name".

Мое регулярное выражение для чисел довольно сложное и допускает числокак "+13.234e-3", "12.34", ".25", "10." или "23,503.14".Если ваши числа имеют более простой формат, вы можете упростить регулярное выражение.

0 голосов
/ 20 сентября 2018

Я предлагаю вам использовать RegEx, например так:

(?<double>[\d.]+)(?<unit>.*)

Он создаст две группы при сопоставлении: 'double' и 'unit', содержащие двойное значение и единицу измерения.

Пример:

1.25632 meter

Здесь группа double будет содержать «1,25632», а группа unit будет содержать «метр»

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...