简体   繁体   English

Int.Parse(String.Split())返回“输入字符串格式不正确”错误

[英]Int.Parse(String.Split()) returns “Input string was not in a correct format” error

I am trying to perform a LINQ query on an array to filter out results based on a user's query. 我正在尝试对数组执行LINQ查询,以根据用户查询过滤出结果。 I am having a problem parsing two int 's from a single string. 我在从单个字符串解析两个int时遇到问题。

In my database, TimeLevels are stored as strings in the format [mintime]-[maxtime] minutes for example 0-5 Minutes . 在我的数据库中,时间级别以字符串形式存储,格式为[mintime]-[maxtime] minutes ,例如0-5 Minutes My user's have a slider which they can select a min and max time range, and this is stored as an int array, with two values. 我的用户有一个滑块,他们可以选择一个最小和最大时间范围,并将其存储为一个带有两个值的int数组。 I'm trying to compare the [mintime] with the first value, and the [maxtime] with the second, to find database entries which fit the user's time range. 我试图将[mintime]与第一个值进行比较,并将[maxtime]与第二个值进行比较,以找到适合用户时间范围的数据库条目。

Here is my C# code from the controller which is supposed to perform that filtering: 这是我应该执行该过滤的来自控制器的C#代码:

RefinedResults = InitialResults.Where(
                x => int.Parse(x.TimeLevel.Split('-')[0]) >= data.TimeRange[0] &&
                int.Parse(x.TimeLevel.Split('-')[1]) <= data.TimeRange[1] &&).ToArray();

My thinking was that it would firstly split the 0-5 Minutes string at the - resulting in two strings, 0 and 5 Minutes , then parse the ints from those, resulting in just 0 and 5 . 我的想法是,它将首先在-处分割0-5 Minutes字符串,从而产生两个字符串05 Minutes ,然后从中解析出整数,从而得到05

But as soon as it gets to Int.Parse, it throws the error in the title. 但是一旦到达Int.Parse,它就会在标题中引发错误。

some of the x.TimeLevel database records are stored as "30-40+ Minutes" . 一些x.TimeLevel数据库记录存储为"30-40+ Minutes" Is there any method just to extract the int ? 有什么方法可以提取int吗?

You could use regular expressions to match the integer parts of the string for you, like this: 您可以使用正则表达式为您匹配字符串的整数部分,如下所示:

RefinedResults = InitialResults
    .Where(x => {
        var m = Regex.Match(x, @"^(\d+)-(\d+)");
        return m.Success
            && int.Parse(m.Groups[1]) >= data.TimeRange[0]
            && int.Parse(m.Groups[2]) <= data.TimeRange[1];
    }).ToArray();

This approach requires the string to start in a pair of dash-separated decimal numbers. 此方法要求字符串以一对以短划线分隔的十进制数字开头。 It would ignore anything after the second number, ensuring that only sequences of digits are passed to int.Parse . 它会忽略第二个数字之后的所有内容,从而确保仅将数字序列传递给int.Parse

The reason your code doesn't work is because string.Split("-", "0-5 Minutes") will return [0] = "0" and [1] = "5 Minutes", and the latter is not parseable as an int. 您的代码无法正常工作的原因是string.Split(“-”,“ 0-5 Minutes”)将返回[0] =“ 0”和[1] =“ 5 Minutes”,而后者是不可解析的作为一个整数。

You can use the regular expression "\\d+" to split up groups of digits and ignore non-digits. 您可以使用正则表达式“ \\ d +”分割数字组并忽略非数字。 This should work: 这应该工作:

var refinedResults = 
(
    from result in InitialResults
    let numbers = Regex.Matches(result.TimeLevel, @"\d+")
    where ((int.Parse(numbers[0].Value) >= data.TimeRange[0]) && (int.Parse(numbers[1].Value) <= data.TimeRange[1]))
    select result
).ToArray();

Here's a complete compilable console app which demonstrates it working. 这是一个完整的可编译控制台应用程序,演示了它的工作原理。 I've used dummy classes to represent your actual classes. 我用虚拟类来代表您的实际类。

using System;
using System.Linq;
using System.Text.RegularExpressions;

namespace ConsoleApplication2
{
    public class SampleTime
    {
        public SampleTime(string timeLevel)
        {
            TimeLevel = timeLevel;
        }

        public readonly string TimeLevel;
    }

    public class Data
    {
        public int[] TimeRange = new int[2];
    }

    class Program
    {
        private static void Main(string[] args)
        {
            var initialResults = new []
            {
                new SampleTime("0-5 Minutes"),
                new SampleTime("4-5 Minutes"), // Should be selected below.
                new SampleTime("1-8 Minutes"),
                new SampleTime("4-6 Minutes"), // Should be selected below.
                new SampleTime("4-7 Minutes"),
                new SampleTime("5-6 Minutes"), // Should be selected below.
                new SampleTime("20-30 Minutes")
            };

            // Find all ranges between 4 and 6 inclusive.

            Data data = new Data();
            data.TimeRange[0] = 4;
            data.TimeRange[1] = 6;

            // The output of this should be (as commented in the array initialisation above):
            //
            // 4-5 Minutes
            // 4-6 Minutes
            // 5-6 Minutes

            // Here's the significant code:

            var refinedResults = 
            (
                from result in initialResults
                let numbers = Regex.Matches(result.TimeLevel, @"\d+")
                where ((int.Parse(numbers[0].Value) >= data.TimeRange[0]) && (int.Parse(numbers[1].Value) <= data.TimeRange[1]))
                select result
            ).ToArray();

            foreach (var result in refinedResults)
            {
                Console.WriteLine(result.TimeLevel);
            }
        }
    }
}

The problem is that you are splitting by - and not also by space which is the separator of the minutes part. 问题是您正在按-而不是作为minutes部分分隔符的空格进行拆分。 So you could use Split(' ', '-') instead: 因此,您可以改用Split(' ', '-')

InitialResults
    .Where(x => int.Parse(x.TimeLevel.Split('-')[0]) >= data.TimeRange[0] 
             && int.Parse(x.TimeLevel.Split(' ','-')[1]) <= data.TimeRange[1])
    .ToArray();

As an aside, don't store three informations in one column in the database. 顺便说一句,不要在数据库的一列中存储三个信息。 That's just a source of nasty errors and bad performance. 那只是令人讨厌的错误和不良性能的根源。 It's also more difficult to filter in the database which should be the preferred way or to maintain datatabase consistency. 在数据库中进行筛选(这是首选方法)或维护数据库一致性也更加困难。


Regarding your comment that the format can be 0-40+ Minutes . 关于您的评论,格式可以是0-40+ Minutes Then you could use... 那你可以用...

InitialResults
    .Select(x => new { 
        TimeLevel = x.TimeLevel, 
        MinMaxPart = x.TimeLevel.Split(' ')[0]
    })
    .Select(x => new { 
        TimeLevel = x.TimeLevel, 
        Min = int.Parse(x.MinMaxPart.Split('-')[0].Trim('+')),
        Max = int.Parse(x.MinMaxPart.Split('-')[1].Trim('+'))
    })
    .Where(x => x.Min >= data.TimeRange[0] && x.Max <= data.TimeRange[1])
    .Select(x => x.TimeLevel)
    .ToArray();

Error happens because of the " Minutes" part of the string. 由于字符串的“分钟”部分而发生错误。 You can truncate the " Minutes" part before splitting, like; 您可以在拆分之前截断“分钟”部分,例如; x.TimeLevel.Remove(x.IndexOf(" ")) then you can split. x.TimeLevel.Remove(x.IndexOf(“”))),则可以拆分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM