4

I have to write a console application for a computer course that I'm taking. The program reads text in from a file using StreamReader, splits the string into single words and saves them in a String array and then prints the words out backwards.

Whenever there is a carriage return in the file, the file stops reading in the text. Could anyone help me with this?

Here is the main program:

using System;
using System.IO;
using System.Text.RegularExpressions;

namespace Assignment2
{
    class Program
    {
        public String[] chop(String input)
        {
            input = Regex.Replace(input, @"\s+", " ");
            input = input.Trim();

            char[] stringSeparators = {' ', '\n', '\r'};
            String[] words = input.Split(stringSeparators);

            return words;
        }

        static void Main(string[] args)
        {
            Program p = new Program();

            StreamReader sr = new StreamReader("input.txt");
            String line = sr.ReadLine();

            String[] splitWords = p.chop(line);

            for (int i = 1; i <= splitWords.Length; i++)
            {
                Console.WriteLine(splitWords[splitWords.Length - i]);
            }

            Console.ReadLine();

        }
    }
}

And here is the file "input.txt":

This is the file you can use to 
provide input to your program and later on open it inside your program to process the input.
Nuwan
  • 1,226
  • 1
  • 14
  • 38
John McDonald
  • 69
  • 1
  • 10

3 Answers3

3

You can use StreamReader.ReadToEnd instead of StreamReader.ReadLine.

// Cange this:
// StreamReader sr = new StreamReader("input.txt");
// String line = sr.ReadLine();

string line;
using (StreamReader sr = new StreamReader("input.txt"))
{
    line = sr.ReadToEnd();
}

The addition of the using block will make sure the input file is closed properly, as well.

Another alterantive would just be to use:

string line = File.ReadAllText("input.txt"); // Read the text in one line

ReadLine reads a single line from the file, and strips off the trailing carraige return and line feed characters.

ReadToEnd will read the entire file as a single string, and preserve those characters, allowing your chop method to work as written.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Thanks a million. Your solution worked perfectly with no hassle at all. :D – John McDonald Aug 06 '13 at 17:25
  • I think it would be even easier to just use [`File.ReadAllText()`](http://msdn.microsoft.com/en-us/library/ms143368.aspx), e.g. `var line = File.ReadAllText("input.txt");` – Matthew Watson Aug 06 '13 at 17:26
3

You are just reading in one line. You need to read all lines till end of file. The following should work:

    String line = String.Empty;
    using (StreamReader sr = new StreamReader("input.txt"))
    {
        while (!sr.EndOfStream)
        {
            line += sr.ReadLine();
        }
    }
Gloria
  • 1,053
  • 8
  • 18
  • What is `Program` and where is `chop` defined? If program is the class which contains main creating an instance is pretty strange... I think you should just use `System.String.Split(char delim)` on line... – evanmcdonnal Aug 06 '13 at 17:22
  • Thank you you very much for your help. The way you've done worked perfectly but I've been told that I should use the way that uses less code. But thanks very much for your answer – John McDonald Aug 06 '13 at 17:24
  • @evanmcdonald Totally agreed.. i was just addressing the issue of the read all lines.. the rest i did not pay attention to as I just copied what the OP has done. These changes need to be suggested to the OP. I will edit my answer to just show the relevant part that i wanted to address to not misguide the OP. – Gloria Aug 06 '13 at 17:26
  • Glad you got your issue resolved. Thanks for the encouragement. You should look into the suggestions @evanmcdonald made in the comments above. – Gloria Aug 06 '13 at 17:31
  • @evanmcdonnal Program is the class and chop is a method which is defined in in Program. I get an error if I try to call chop without creating an object – John McDonald Aug 06 '13 at 17:41
  • @JohnMcDonald yeah I found that in the docs. That's an odd way of doing it but it works. – evanmcdonnal Aug 06 '13 at 17:47
  • @evanmcdonnal What is the normal way of doing it? – John McDonald Aug 06 '13 at 18:01
  • @JohnMcDonald using the `Split` method on the string class. Creating an instance of `Program` is odd and isn't necessary since you already have string instances on which you can call split. Also, it's relatively difficult to find the documentation for `chop` and unlike `Split` every professional C# dev won't know exactly what it does without having to look at them. – evanmcdonnal Aug 06 '13 at 18:08
  • @evanmcdonnal Oh sorry my bad. I know that I can use the 'Split' method on the string class. This is a programming challenge that I was given and part of the challenge is to create the method chop() that takes a string argument and splits it. – John McDonald Aug 06 '13 at 18:13
  • @JohnMcDonald I see. Well that methods implementation could be nothing more than - `public string[] chop(string s) { return s.Split(' '); }`. Unless your professor is requiring that you do more parsing yourself (as in iterating over a character array) I would suggest using that implementation. Also, you shouldn't make `chop` an instance method, either make it static or put change it's scope so it's available to main. – evanmcdonnal Aug 06 '13 at 18:17
  • 1
    @evanmcdonnal I changed chop to static and now it doesn't require an object to be called. I have to remove extra spaces from the application so that each word is displayed under the previous word without having any gaps between – John McDonald Aug 06 '13 at 18:26
2

The problem is that you're calling ReadLine() which does exactly that, it reads til it encounters a carriage return (you have to call it in a loop).

Typically if you want to read a file line by line with StreamReader the implementation looks more like this (from msdn);

        using (StreamReader sr = new StreamReader("TestFile.txt")) 
        {
            string line;
            // Read and display lines from the file until the end of  
            // the file is reached. 
            while ((line = sr.ReadLine()) != null) 
            {
                Console.WriteLine(line);
            }
        }

The condition in the while loop ensures that you will read til the end of the file because ReadLine will return null if there is nothing to read.

Another option is just to use File.ReadAllLines(MyPath) which will return an array of strings, each element being one line in the file. To give a more complete example of that;

  string[] lines = File.ReadAllLines(MyFilePath);
  foreach(string line in lines)
  {
        string[] words = line.Split(' ').Reverse();
        Console.WriteLine(String.Join(" ", words));
  }

Those three lines of code do the following; Reads the entire file into a string array where each element is a line. Loops over that array, on each line we split it into the words and reverse their order. Then I join all the words back together with spaces between them and print it to the console. If you want the whole file in reverse order then you need to start at the last line instead of the first, I'll leave that detail to you.

evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115