-2

I am trying to read text from a data file. Each line of text is shown below:

Group_5, 4911.66, 4910.274, 13781.725, 2018

I want to parse the string so that I can use the values for my calculations. The string array Str is only collecting the first term Group_5.

private void button1_Click(object sender, EventArgs e)
{
    string Line;
    string path = Survey_File.Text;
    int i, j;
    double X = 0, Y = 0, Z = 0, X_Last = 0.0, Y_Last = 0.0, Z_Last = 0.0, MD = 0, increment;
    string[,] StrMatrix = new string[1000000, 3];
    string[] Str = new string[5];
    string[] Strings = new string[1000000];
    string content;
    i = j = 0;
    StreamReader ReadSurveyFile = new StreamReader(Survey_File.Text);
    while ((Line = Convert.ToString(ReadSurveyFile.ReadLine())) != null)
    {
        Line = Convert.ToString(Line);
        Str = Line.Split(',', ',', ',', ',');
        Strings[i] = Line;
        Str = Strings[i].Split(',');
        //X = Convert.ToDouble(Str[1]);
        //Y = Convert.ToDouble(Str[2]);
        //Z = Convert.ToDouble(Str[3]);
        increment = Math.Sqrt((X - X_Last) * (X - X_Last) + (Y - Y_Last) * (Y - Y_Last) + (Z - Z_Last) * (Z - Z_Last));
        X_Last = X;
        Y_Last = Y;
        Z_Last = Z;
        MD = MD + increment;
        i++;
        Console.WriteLine(Str[1]); // Error Here
    }
    Console.ReadLine();
    MessageBox.Show("Measured Depth = "+Convert.ToString(MD));
}

The error message that I receive is

"IndexOutOfRangeException was unhandled."

This doesn't make sense to me because I dimensionalized the string array Str properly. The error appears where I specified above.

Drise
  • 4,310
  • 5
  • 41
  • 66
Reid
  • 1
  • 4
    That's not C, it's C# - please tag your questions correctly – UnholySheep Mar 12 '18 at 19:04
  • Appologies, I didn't notice this was not c++, moved to C#. – Drise Mar 12 '18 at 19:13
  • 2
    In the iteration of the loop where this breaks, what is the *exact value* of `Line`? Also, why are you doing the `Convert.ToString()` calls on `ReadSurveyFile.ReadLine()`, and then again on `Line`? These should already be strings since that is what `ReadLine()` returns.. – Broots Waymb Mar 12 '18 at 19:18
  • Please re-read [MCVE] guidance. And consider checking method documentation before asking the question... You definitely have your own idea what `Str = Line.Split(',', ',', ',', ',');` does, but that is not reflected in the post - so not possible to help in meaningful way. (Could be closed as dulplicate of "IndexOutOfRangeException - how to fix", but it probably not what you actually having problem to understand) – Alexei Levenkov Mar 12 '18 at 19:20
  • 2
    Learn what [`String.Split`](https://msdn.microsoft.com/en-us/library/b873y76a(v=vs.110).aspx) does before you try to use it. Hint: it doesn't [parse comma-separated values](http://www.secretgeek.net/csv_trouble); use a [CSV parser](https://stackoverflow.com/questions/906841/). – Dour High Arch Mar 12 '18 at 19:30

6 Answers6

2

It's not clear what you're trying to do, but this should be much easier to work with. It cleans up much of the confused mess between arrays and values in the original.

private void button1_Click(object sender, EventArgs e)
{
    double X_Last = 0.0, Y_Last = 0.0, Z_Last = 0.0;
    double MD = 0.0;

    var lines = File.ReadLines(Survey_File.Text).Select(l => l.Split(','));
    foreach(var line in lines)
    {
        double X = double.Parse(line[1].Trim());
        double Y = double.Parse(line[2].Trim());
        double Z = double.Parse(line[3].Trim());

        double XDiff = X - X_Last;
        double YDiff = Y - Y_Last;
        double ZDiff = Z - Z_Last;

        double increment = Math.Sqrt((XDiff * XDiff) + (YDiff * YDiff) + (ZDiff * ZDiff));
        MD += increment;

        X_Last = X;
        Y_Last = Y;
        Z_Last = Z;

        Console.WriteLine(MD.ToString());
    }
    Console.ReadLine();
    MessageBox.Show("Measured Depth = " + MD.ToString());
}

Note I don't normally condone the use of Split() for handling CSV data. It's slow and error-prone. But the sample data seems fairly safe in this case, and Split() is the least of concerns here.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • Due respect to someone with 286k reputation; but I think this will suffer from the same exception, since I think the problem is a blank line (see my answer). – Richardissimo Mar 12 '18 at 20:13
  • That's possible. I've been thinking that an array with four commas was confusing the Split() function from getting any lines right, never having tried something so odd myself. But a blank line or other bad data could do this, too... in which case it's easy enough to add a `.Where()` before the `.Select()` – Joel Coehoorn Mar 12 '18 at 20:20
  • It was really tempted to add another `.Select()` call to then convert the array to a Tuple with 3 doubles. – Joel Coehoorn Mar 12 '18 at 20:25
  • And while that's absolutely brilliant, it wouldn't help the OP understand the problem that they're suffering from. There are currently 6 answers here; but only one is answering the question that was asked. – Richardissimo Mar 12 '18 at 20:31
1

That sourcefile looks like a CSV file. While you can parse them with Split, I would advise using a proper CSV reader. Latest when you run into oddities like escaped seperators, broke lines or multi line fields, simple split will break down. (the broken lines case is propably what you have here btw.)

There is a built in CSV parser, but it is somewhat hidden in Visual Basic Sourcefiles (https://coding.abel.nu/2012/06/built-in-net-csv-parser/)

There is however a lot of 3rd party solutions, this one seems particulary promising: http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader

If the file is large (and your 3rd party CSV parser code does not do so already) I would advise for using the Enumerator approach to itterate over the lines. Large CSV files are known to run into Memory Limit like the old 2 GiB one and even if that is not an issue, it should be slightly faster using the Enumerator.

Christopher
  • 9,634
  • 2
  • 17
  • 31
1

The error that you're getting is a classic. The error is saying that you're trying to use an index which doesn't exist when you are doing "Str[1]". In other words, at the point of execution, 'Str' doesn't have two items in it.

Notice that Str is of type "string[]" (an array of strings - note that this does not fix the size of the array), and you are initialising it to point at an array of 5 strings. However, when you assign "Str = Strings[i].Split(',');", it will assign Str to the result of that split, which will be the size of how many items are given by splitting the string; and the array of 5 strings is discarded.

Since you are looping through each line of the file at a time, my guess would be that you are reaching a line which doesn't have two comma-separated items in it. My guess would be that it is probably an empty line in your file. You can prove this by stepping through with a debugger, or put Console.WriteLine("Line " + i + ":" + Line); on the line before the crash.

So despite the question, Split is working perfectly. The reason for the exception is the use of the indexer without being sure how many items are in the array (which is always the cause of an IndexOutOfRangeException).

P.S. "StreamReader" is disposable, so you should put it in a "using" block.

Richardissimo
  • 5,596
  • 2
  • 18
  • 36
0

Try

Str = Line.Split(',');

instead of

Str = Line.Split(',', ',', ',', ',');

Then Str should be long enough so that Str[1] ("4911.66") exists, and should prevent the error.

  • 1
    This fixes one problem, but the question has several other issues to deal with, too :( – Joel Coehoorn Mar 12 '18 at 19:34
  • 1
    Of course I could go ahead and tell him that his Code isn't up to my standards, but that wasn't the question, the question was just why his Split function doesn't result in the result he expects. My Answer should solve his question. I agree that your answer gives far better/cleaner code though. – Holicone Mar 12 '18 at 19:36
0

You probably don't need to do these:

Line = Convert.ToString(Line);   //Already happens in the readline in loop.
Str = Line.Split(',', ',', ',', ',');  // do Line.Split(',') instead

From this point on, it seems OK, but I suggest doing something to verify you are getting Line read in correctly. If you are only getting the first word.

Secondly, it doesn't matter what you initiaize Str as... Calling String.Split() will assign Strto a new array with the results of the split method.

//Somewhere above:
string[] Str = new string[5];

Strings[i] = Line;  
Str = Strings[i].Split(',');  //reassigns Str to a new array created by String.Split(',')
Samuel
  • 61
  • 5
-1

Try this:

Str = Line.Split(new char[] {','}, StringSplitOptions.None);
Floern
  • 33,559
  • 24
  • 104
  • 119
  • Could you indicate where in the code you mean? It looks like you want to put the line inside the while statement, should the rest of the code remain? – Rob Sedgwick Mar 12 '18 at 22:18