-1

So I have a text file that I need to order its rows by Date and Time as show in the attached screenshot column and I am not sure how

any idea please?

Screenshot

this is what i tried so far

File
    .ReadLines(newfile)
    .OrderBy(line => DateTime.TryParseExact(
        line.Split("  ",StringSplitOptions.RemoveEmptyEntries),
        "yyyy MMM d H:m:s.fff", CultureInfo.InvariantCulture, 
        DateTimeStyles.AssumeLocal, out var dt) 
            ? dt
            : DateTime.MaxValue);

new update

OrderFileLines("MyFile").OrderBy(line => DateTime.ParseExact(line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[2], "yyyy MMM dd HH:mm:ss.fff", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal));

static IEnumerable<string> OrderFileLines(string stream)
        {
            using (StreamReader reader = new StreamReader(stream, true))
            {
                for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
                {
                    yield return line;
                }
            }
        }

condoor
  • 3
  • 3
  • You will probably need to parse the dates with format `YYYY MMM DD HH:mm:ss.fff`. Can you paste a source sample and an expected result (as text instead of image)? – Rafalon Feb 22 '23 at 15:04
  • What type is `myFile`? – Rafalon Feb 22 '23 at 15:23
  • What is the problem? Compile error, runtime exception, invalid output? Please describe the problem (and don't use screenshots - plain text is better for copy/paste and for screenreaders). – Rufus L Feb 22 '23 at 15:39
  • `Split` returns a string array, but you should be passing a string to `TryParseExact`. You might try including the index of the item in the array that contains the date, i.e: `line.Split(...)[1]` – Rufus L Feb 22 '23 at 15:41
  • From @Shinglington The .OrderBy() LINQ query allows you to do something like .OrderBy(GetDate), where in your own custom GetDate(string line) method, you could extract the components of the date using .Split(" ") and then return it as maybe a DateTime type? – James Risner Feb 22 '23 at 16:31
  • Why you try to sort text month and not number? There is ISO format `YYYY-MM-DD HH:mm:ss` - use it and sort. – i486 Mar 01 '23 at 14:30
  • @i486 still not working, – condoor Mar 01 '23 at 14:45

2 Answers2

1

You should extract date, parse it and then order by this date. I can't see what is the delimeter in your file. If it's tabulation '\t':

using System.Globalization;
using System.Linq;

...

// Assuming myFile is IEnumerable<string>
var sortedLines = myFile
  .OrderBy(line => DateTime.TryParseExact(
      line.Split('\t', StringSplitOptions.RemoveEmptyEntries)[1],
     "yyyy MMM d H:m:s.fff",
      CultureInfo.InvariantCulture,
      DateTimeStyles.AssumeLocal, out var dt)
        ? dt
        : DateTime.MaxValue); // Incorrect dates will be in the end

If the delimiter is a double space " " then

var sortedLines = myFile
  .OrderBy(line => DateTime.TryParseExact(
      line.Split("  ", StringSplitOptions.RemoveEmptyEntries)[1],
     "yyyy MMM d H:m:s.fff",
      CultureInfo.InvariantCulture,
      DateTimeStyles.AssumeLocal, out var dt)
        ? dt
        : DateTime.MaxValue);

If myFile is a name of the file you should put it as

using System.IO;

...

var sortedLines = File
  .ReadLines(myFile)
  .OrderBy(...);

Edit: If myFile is FileStream you, technically, can enumerate it like this

static IEnumerable<string> FileLines(FileStream stream) {
  using StreamReader reader = new StreamReader(stream, leaveOpen: true);

  for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
    yield return line;
}            

and then

var sortedLines = FileLines(myFile)
  .OrderBy(...);

but I doubt if you really want Stream here

Edit2: If we don't know what the delimiter is (in the worst case it is space) we can match date with a help of regular expression:

  using System.Text.RegularExpressions;

  ...

  Regex regex = new Regex("[0-9]{4} [A-Z][a-z]+ [0-9]{1,2} [0-9:.]+");

  ...

  .OrderBy(line => DateTime.TryParseExact(
      regex.Match(line).Value ?? "",
     "yyyy MMM d H:m:s.fff",
      CultureInfo.InvariantCulture,
      DateTimeStyles.AssumeLocal, out var dt)
        ? dt
        : DateTime.MaxValue);
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • Tried this already at the start but it doesn't allow me to use .Split and yes it's double space delimiter – condoor Feb 22 '23 at 15:22
  • If `myFile` is a `File` object, maybe you should use `myFile.ReadAllLines().OrderBy(...` – Rafalon Feb 22 '23 at 15:24
  • its a FileStream sorry didn't explain it – condoor Feb 22 '23 at 15:25
  • this is very close from what i am trying to do but still can't split lines – condoor Feb 22 '23 at 15:32
  • @condoor: to *split* line we want *delimiter* which can't be read from the *screenshot* (is it tabulation? double space, something else?). Please, provide an *except* of the file – Dmitry Bychenko Feb 22 '23 at 15:37
  • trying to post examples but stackover flow doesn't allow me to do multiple edits how ever this is an example of a row {Sll} 2023 Jan 13 10:13:26.674 --> [MySoftwareName][myFunction] – condoor Feb 22 '23 at 15:45
  • unfortunately found that its not working – condoor Mar 01 '23 at 14:24
0

I suggest to split your code and isolate the logic to calculate the timestamp from a single line, then use it in your code.

A function like the following could give you a valid timestamp from a line. You could try the regex directly in regex101.com with the lines of your file.

    static Regex MatchRegex = new Regex(@"^\{[a-zA-Z0-9]+\}[\t\s]+([0-9]{4}\s[a-zA-Z]{3}\s[0-9]{2}\s[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3})[\s\t].+$");
    static DateTime GetTimestamp(string line) {
        var match = MatchRegex.Match(line);
        if (!match.Success) return DateTime.MaxValue;
        var dateString = match.Groups[1].Value;
        if (DateTime.TryParse(dateString, out var timestamp))
            return timestamp;
        return DateTime.MaxValue;

    }

Then you could use this function in the OrderBy

var sortedLines = File
    .ReadLines(sourceFileName)
    .OrderBy(line => GetTimestamp(line));
var content = string.Join(Environment.NewLine, sortedLines);
File.WriteAllText(destinationFilename, content);

In this way you could test and debug single parts.