Click here to Skip to main content
15,041,025 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Orginal text file [NGL.txt]:

11000.000      15
          -118.520 366.000 -74.246 364.000 -58.330 362.000 -44.711 361.000
           -12.755 358.283 -2.798 360.000 8.160 362.000 19.474 358.000
            32.417 366.000 39.590 368.000 62.812 366.000 68.217 364.000
            73.621 362.000 83.306 360.000 90.544 358.000
 11025.000      15
          -145.074 368.000 -99.833 366.000 -65.355 364.000 -53.492 362.000
           -38.758 358.000 -20.190 358.726 -1.623 360.000 9.696 362.000
            21.824 364.000 34.559 366.000 47.717 368.000 61.846 366.000
            70.839 364.000 87.834 362.000 102.282 360.000
 11050.000      14
          -165.336 372.000 -156.975 370.000 -129.751 368.000 -88.502 366.000
           -66.098 364.000 -51.473 362.000 -32.173 360.000 -15.167 360.000
             1.839 360.000 9.759 362.000 20.916 364.000 37.497 366.000
            52.258 368.000 91.663 370.000
END


The above file [NGL.txt] is a text file which contains coordinate points x & y space delimited [-118.520 366.000 . . .]and grouped by kilometric markers interval every 25 meters here are 11000, 11025 & 11050 respectively, number of coordinate pointes shown at RHS of the intervals on the first group equals 15, second one is 15 third group is 14.
My code gave me the file [G2_point.txt]:
11000.000     15
          -118.520
          366.000
          -74.246
          364.000
           . . .
           . . .
           90.544
          358.000
11025.000     15
          -145.074
          368.000
          -99.833
          366.000
          . . .
          . . .
          102.282
          360.000
11050.000     14
          -165.336
          372.000
          -156.975
          370.000
          . . .
          . . .
          91.663
          370.000


Instead, I need output file looks like this:
11000.000     15
          -118.520 366.000
          -74.246 364.000
           . . .
           . . .
            90.544 358.000
11025.000     15
          -145.074 368.000
          -99.833 366.000
          . . .
          . . .
          102.282 360.000
11050.000     14
          -165.336 372.000
          -156.975 370.000
           . . .
           . . .
           91.663 370.000


What I have tried:

C#
static void Main(string[] args)
        {
            StreamWriter sw = new StreamWriter("..\\..\\G2_point.txt");
            using (var sr = new StreamReader("..\\..\\NGL.txt"))
            {
                while (sr.Peek() >= 0)
                {
                    string line = sr.ReadLine();
                    
                    if (line != "END")
                    {
                        var numberOfSpaces = line.TakeWhile(c => c == ' ').Count();

                        string[] items = line.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        if (items.Length == 2 && numberOfSpaces == 1)
                        {
                            sw.WriteLine(String.Format(" {0}     {1}", items[0], items[1]));
                        }
                        else if ((numberOfSpaces >= 10 && numberOfSpaces <= 14) && (items.Length >= 2 || items.Length <= 8))
                        {
                            int i = 0;
                            foreach (var item in items)
                            {
                                sw.WriteLine(String.Format("          {0}", item));
                                i++;
                            }

                        }

                        else
                            throw new Exception(string.Format("invalid line {0}", line));
                    }
                }
            }
            sw.Close();
        }
Posted
Updated 30-Apr-21 5:00am
v2

I'd change the way I did this: read your data and build an "internal model" of what it should look like using classes - possibly something like this:
C#
public class FullRow
   {
   public string Header1;
   public string Header2;
   List<Coord> Coords = new <List<Coord>;
   }
public class Coord
   {
   public string X;
   public string Y;
   }
And then create a List of FullRow instances to hold it all.
Then read your data into those classes, check it read it ok, and override ToString in both classes to "prepare" the data (including your spaces).
That way, your data starts to "organise itself" and instead of a rather messy "read and print differently" method, you end up with cleaner code:
Coord returns the two values, separated by a space, FullRow returns as string with your two header values, and loops though it's collection adding spacing and line breaks to the Coord ToString return.

Keep It Simple: give each method one job to do and let data handle itself: Read all the data into an array, and process the whole array as input (which lets you "look ahead" to see if you are at the end, instead of reading a line at a time).
When you try to combine four functions in one method (reading the file, breaking the file up, formatting the result, and outputting the final file data) you end up with confusion and that makes it hard to work with, hard to test, and hard to maintain.
   

It is not that difficult. As Griff states it is better to feed the data into a class and then print it out into whatever format you require. Something like this.


C#
public class Entry
   {
       public string Heading;
       public int EntryCount = 0;
       public List<(string x, string y)> Coordinates = new List<(string x, string y)>();
       public override string ToString()
       {
           StringBuilder sb = new StringBuilder($"{Heading}   {EntryCount}  \r\n");
           foreach (var (x, y) in Coordinates)
           {
               sb.AppendLine($"\t{x} {y}");
           }
           return sb.ToString();
       }
   }

Read the lines from a file and clean up the extraneous spaces. Get the first line of an entry and calculate out the number of coordinates in the section. Split the following lines and extract the coordinates from them until you have the required number. Instantiate a new Entry class using the data you have extracted and add it to a list of entries. Repeat until all the data has been read. Iterate over the list of entries and print them out using the ToString method.


C#
static void Main(string[] args)
 {
     List<Entry> entries = new List<Entry>();
     var fileContents = File.ReadAllLines(@"C:\Temp\Ftest.txt");
     var cleanedLines = fileContents.Select(l => string.Join(" ", l.Split(' ',
                       StringSplitOptions.RemoveEmptyEntries))).ToArray();
     int lineCount = 0;
     while (lineCount < cleanedLines.Length - 1)
     {
         var headings = cleanedLines[lineCount].Split(' ');
         int entryCount = int.Parse(headings[1]) * 2;
         lineCount++;
         int end = lineCount + entryCount;
         List<string> coords = new List<string>();
         while (coords.Count < entryCount)
         {
             var lineCoors = cleanedLines[lineCount].Split(' ');
             coords.AddRange(lineCoors);
             lineCount++;
         }
         Entry record = new Entry() { Heading = headings[0], EntryCount = entryCount / 2 };
         record.Coordinates = new List<(string x, string y)>();
         for (int i = 0; i < coords.Count - 1; i++)
         {
             record.Coordinates.Add((coords[i], coords[i + 1]));
         }

         entries.Add(record);
     }
     foreach (var e in entries)
     {
         Console.WriteLine(e);
     }
     Console.ReadLine();
 }

Here is the complete code of a version that does not use tuples.


C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace TestPrint
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Entry> entries = new List<Entry>();
            var fileContents = File.ReadAllLines(@"C:\Temp\Ftest.txt");
            var cleanedLines = fileContents.Select(l => string.Join(" ", l.Split(' ',                          StringSplitOptions.RemoveEmptyEntries))).ToArray();
            int lineCount = 0;
            while (lineCount < cleanedLines.Length - 1)
            {
                var headings = cleanedLines[lineCount].Split(' ');
                int entryCount = int.Parse(headings[1]) * 2;
                lineCount++;
                int end = lineCount + entryCount;
                List<string> coords = new List<string>();
                while (coords.Count < entryCount)
                {
                    var lineCoors = cleanedLines[lineCount].Split(' ');
                    coords.AddRange(lineCoors);
                    lineCount++;
                }
                Entry record = new Entry() { Heading = headings[0], EntryCount = entryCount / 2 };
                record.Coordinates = new List<Coordinate>();
                for (int i = 0; i < coords.Count - 1; i++)
                {
                    record.Coordinates.Add(new Coordinate(coords[i], coords[i + 1]));
                }

                entries.Add(record);
            }
            foreach (var e in entries)
            {
                Console.WriteLine(e);
            }
            Console.ReadLine();
        }
    }
    public class Entry
    {
        public string Heading;
        public int EntryCount = 0;
        public List<Coordinate> Coordinates = new List<Coordinate>();
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder($"{Heading}   {EntryCount}  \r\n");
            foreach (var c in Coordinates)
            {
                sb.AppendLine($"\t{c.X} {c.Y}");
            }
            return sb.ToString();
        }
    }
  // use custom class to store the coordinates 
     public class Coordinate
    {
        public string X;
        public string Y;
        public Coordinate(string x, string y)
        {
            X = x;
            Y = y;
        }
    }

}
   
v3
Comments
essukki 1-May-21 4:30am
   
Uncompilable code...!!
George Swan 1-May-21 10:42am
   
you need the following 'using' statements
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
essukki 1-May-21 14:20pm
   
Thank you a lot George my VS 2017 has problem with "
'Tuple' does not exist in the namespace 'System.Runtime.CompilerServices' (are you missing an assembly reference?),
"
George Swan 1-May-21 14:58pm
   
Can you update to Visual Studio 2019 Version 16.9.4 and .Net Framework 4.8?
essukki 1-May-21 15:35pm
   
I will try
George Swan 1-May-21 15:47pm
   
updated the solution to avoid tuples
essukki 2-May-21 5:36am
   
Thank you again Mr.George Swan.
This is amazing but this line of your code:
int entryCount = int.Parse(headings[1])•2;
needs some repair I
Received this message:
System.FormatException:'Input string was not in a correct format'..
Perhaps the defect in my Visual Studio 2017..
George Swan 2-May-21 7:41am
   
Have a look at the headings and see if you have a entry count value that cannot be converted to an int. All lines format fine with your example data. Or try debugging
essukki 2-May-21 11:02am
   
This part of line prevent compilation to go through
StringSplitOptions.RemoveEmptyEntries..
Message:
Argument2: cannot convert from 'System.StringSplitOptions' to char
George Swan 2-May-21 12:19pm
   
Try this version
var cleanedLines = fileContents.Select(l => string.Join(" ", l.Split(new char[] { ' ' },
StringSplitOptions.RemoveEmptyEntries))).ToArray();
essukki 2-May-21 14:39pm
   
Yes that it is..
Now every things are perfect thank you Mr. George for your patience and helping..

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900