C# 正在修复System.FormatException

C# 正在修复System.FormatException,c#,debugging,formatexception,C#,Debugging,Formatexception,我正在编写一个代码,它将查看名为a的文本文件中的一个组,如果代码中的一行包含短语“Savings Found”,它将写出该行,如果节省了30%或更多,它将在前面放置一个星号,如果它包含30%或更多,并且节省了500美元或更多,它将放置两个星号。下面我有一个示例数据,一个控制台需要的外观示例,以及迄今为止我所拥有的代码: string find = "Savings found:"; foreach (var line in a.Where(w => w.Contains(f

我正在编写一个代码,它将查看名为a的文本文件中的一个组,如果代码中的一行包含短语“Savings Found”,它将写出该行,如果节省了30%或更多,它将在前面放置一个星号,如果它包含30%或更多,并且节省了500美元或更多,它将放置两个星号。下面我有一个示例数据,一个控制台需要的外观示例,以及迄今为止我所拥有的代码:

    string find = "Savings found:";
    foreach (var line in a.Where(w => w.Contains(find)))
       {
          var subStr = line.Substring(line.IndexOf(find) + find.Length);
          var startIndex = subStr.IndexOf('(');
          var endIndex = subStr.IndexOf(')');

          var savings = double.Parse(subStr.Substring(0, startIndex - 1).Trim());
          var percent = double.Parse(subStr.Substring(startIndex + 1, endIndex - startIndex - 2).Trim());

          Console.WriteLine("{0}{1}{2}", (percent >= 30) ? "*" : string.Empty,

          (percent >= 30 && savings >= 500) ? "*" : string.Empty,
                                                        line);
         }
样本数据/示例

* 5/21/2015 11:55:56 PM | Batch 6|386/767|50.33 %|CH2M-R|Processed NXRMN5...Checking refundable and non-refundable fares. Traditional Booking. Inside ticketing window. Minimum Savings Required: $131.00. Actual Savings: $257.18. Savings found: $257.18 (11.55 %). Savings were previously found.
我遇到的问题是我遇到了FormatException错误,我想我知道问题是什么。问题是subString的值是257.18及其后的所有值。我不想要后面的一切,我只想要号码。我能做些什么来去除那些多余的垃圾,这样它就可以编译了


这个问题类似于前面提出的问题,但是在回答中,我得到了ArgumentIndexOutOfBounds异常,试图解决它,但实际上没有解决问题,因此这个问题背后的推理是这样的。

我假设您想要“储蓄发现”之后的数字和十进制值: 正则表达式应该有所帮助。也许有比这更好的方法,但这应该行得通

 string find = "Savings found:";
    foreach (var line in a.Where(w => w.Contains(find)))
       {
          //line = 5/21/2015 11:55:56 PM | Batch 6|386/767|50.33 %|CH2M-R|Processed NXRMN5...Checking refundable and non-refundable fares. Traditional Booking. Inside ticketing window. Minimum Savings Required: $131.00. Actual Savings: $257.18. Savings found: $257.18 (11.55 %). Savings were previously found."
          Regex regex = new Regex(@"Savings found:\s\$[0-9]*.[0-9]{2}\s*\([0-9]*.[0-9]{2} %\)");
          Match match = regex.Match(line);
          var savingsFoundSection = match.Value;

          MatchCollection matches = Regex.Matches(savingsFoundSection, @"[0-9]*\.[0-9]{2}");
          String savingsString = matches[0].Value;
          String percentString = matches[1].Value;
          //savingString = "257.18"
          //precentString = "11.55"

          var savings = double.Parse(savingsString);
          var percent = double.Parse(percentString);

          Console.WriteLine("{0}{1}{2}", (percent >= 30) ? "*" : string.Empty,

          (percent >= 30 && savings >= 500) ? "*" : string.Empty,
                                                        line);
         }

您可以使用regex进行以下操作:

foreach(string line in a)
{
    Match m = Regex.Match(line, @"Savings\s+found:\s*\$(?<savings>\d+\.\d+)\s*\(\s*(?<percent>\d+\.\d+)\s*%");
    if (m.Success)
    {
        decimal savings = decimal.Parse(m.Groups["savings"].Value, CultureInfo.InvariantCulture);
        decimal percent = decimal.Parse(m.Groups["percent"].Value, CultureInfo.InvariantCulture);
        string prefix = string.Empty;
        if (percent >= 30)
        {
            if (savings >= 500)
                prefix = "**";
            else
                prefix = "*";
        }
        Console.WriteLine(prefix + line);
    }
}
foreach(a中的字符串行)
{
Match m=Regex.Match(第行,@“储蓄\s+已找到:\s*\$(?\d+\.\d+.\s*\(\s*(?\d+\.\d+.\s*%));
如果(m.成功)
{
decimal savings=decimal.Parse(m.Groups[“savings”].Value,CultureInfo.InvariantCulture);
小数百分比=decimal.Parse(m.Groups[“percent”].Value,CultureInfo.InvariantCulture);
字符串前缀=string.Empty;
如果(百分比>=30)
{
如果(节省>=500)
前缀“**”;
其他的
前缀=“*”;
}
Console.WriteLine(前缀+行);
}
}

您似乎能够重现错误。太好了!重现性问题通常很容易修复

假设您没有OzCode或ReSharper等其他工具,这将是调试和修复它的方法:

一旦你知道了错误发生的那一行,就让语句变得更简单。也就是说,把它分解成更小的部分。在你的例子中

var savings = double.Parse(subStr.Substring(0, startIndex - 1).Trim());
做了太多的事情,所以你不知道问题是什么。将其分为:

var savingsString = subStr.Substring(0, startIndex - 1).Trim();
var savings = double.Parse(savingsString);
因为在调试过程中,您可以向
savingstring
添加一个手表,并查看它是否正确

您可以考虑一下“$257.18”无法解析的原因,并找到相应的对策。对于以前的代码,您甚至不知道导致问题的输入

潜在对策:

  • 删除美元:
    。替换(“$”,“”)
  • 稍后启动子字符串:
    subStr.子字符串(1,…)
  • savingstring=savingsString.Trim(“$”);
    如果不能确定它是在开头还是结尾
从您的程序代码来看,似乎您知道所有必需的方法,只是不知道如何调试

继续使用这种方法,您将能够修复代码中的所有问题,甚至将来的问题


而且:我不能推荐正则表达式。它们不可读,没有人想维护它们。

不幸的是,这不起作用。当我运行调试器时,var savings行弹出ArgumentOutOfRangeException。表示长度不能小于0whoops,请稍等片刻仍有一个System.ArgumentOutOfRangeException,但这次显示Specified参数超出了有效值的范围。此时savingsString行出现错误。savingsString行中存在相同问题。如果更简单,savingsString值的读数为445.00,SavingsFoundSection的值为“”,与[0]匹配,它是否抛出了System.ArgumentoutOfRangeException类型的异常,以便可以编译这似乎是一个运行时错误,而不是编译器错误。@ThomasWeller这是一个运行时错误。我为这个错误道歉。谢谢你指出这一点,我很感激。我猜你在解析方法中包含了
$
%
,但它们不起作用。@ThomasWeller你是对的。这些,加上额外的东西都在里面,我所做的一切我怀疑Find/Substring/Replace的组合是否比regex更具可读性。我同意@UlugbekUmirov,你建议他进行单元测试?或者一次测试一个单元?因为它们不是同一件事。@JasonPortnoy:我同意。联合国的概念它可能对OP来说太多了。移除该部分。