8 Replies - 555 Views - Last Post: 28 December 2012 - 02:06 PM Rate Topic: -----

#1 C.Andrews  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 169
  • Joined: 18-October 12

There has to be a better way to do this...

Posted 27 December 2012 - 12:00 PM

I have this block of code that works perfectly and does exactly what I need it to do, but I feel like it's a dirty, awful hack of a solution and there must be a better way to get it to work. What I'm doing is reading in a SAS log file and writing the contents into a rich text box. I'm preserving the color coding that one normally sees in SAS output by checking each line as it's read to see if it meets certain conditions, then changing the text color to match the coding scheme used in SAS; because the messages written in the log can wrap beyond a single line, I'm also checking to see if the next line after a color coded line is indented to indicate that it's still a part of the previous line (which is how the output from SAS is formatted) and needs to be colored as well.

I'm also collecting the first line of any warnings or errors found in the output into an array in order to display an error/warning summary to the user once the log is done being printed to the textbox. The resulting code looks like this:

        oInFile = oInFileO.OpenTextFile(chrDrive & ":\SASH2\Log.log", IOMode.ForReading)

        strSText = ""
        Do While Not oInFile.AtEndOFStream
            If strSText Like "ERROR:*" Then
                aryErrors.Add(strSText)
                With frmSAS.txtLog
                    .Selectionstart = .TextLength
                    .SelectionColor = Color.Red
                    .AppendText(strSText & vbNewLine)
                    .SelectionColor = .ForeColor
                End With
                strSText = oInFile.Readline
                If Len(strSText) > 5 Then
                    Do While strSText Like "    *" And Not oInFile.AtEndOFStream
                        With frmSAS.txtLog
                            .Selectionstart = .TextLength
                            .SelectionColor = Color.Red
                            .AppendText(strSText & vbNewLine)
                            .SelectionColor = .ForeColor
                        End With
                        strSText = oInFile.Readline
                    Loop
                End If
            ElseIf strSText Like "NOTE:*" Then
                With frmSAS.txtLog
                    .Selectionstart = .TextLength
                    .SelectionColor = Color.Blue
                    .AppendText(strSText & vbNewLine)
                    .SelectionColor = .ForeColor
                End With
                strSText = oInFile.Readline
                If Len(strSText) > 5 Then
                    Do While strSText Like "    *" And Not oInFile.AtEndOFStream
                        With frmSAS.txtLog
                            .Selectionstart = .TextLength
                            .SelectionColor = Color.Blue
                            .AppendText(strSText & vbNewLine)
                            .SelectionColor = .ForeColor
                        End With
                        strSText = oInFile.Readline
                    Loop
                End If
            ElseIf strSText Like "WARNING:*" Then
                aryErrors.Add(strSText)
                With frmSAS.txtLog
                    .Selectionstart = .TextLength
                    .SelectionColor = Color.Green
                    .AppendText(strSText & vbNewLine)
                    .SelectionColor = .ForeColor
                End With
                strSText = oInFile.Readline
                If Len(strSText) > 5 Then
                    Do While strSText Like "    *" And Not oInFile.AtEndOFStream
                        With frmSAS.txtLog
                            .Selectionstart = .TextLength
                            .SelectionColor = Color.Green
                            .AppendText(strSText & vbNewLine)
                            .SelectionColor = .ForeColor
                        End With
                        strSText = oInFile.Readline
                    Loop
                End If
            Else
                With frmSAS.txtLog
                    .Selectionstart = .TextLength
                    .SelectionColor = Color.Black
                    .AppendText(strSText & vbNewLine)
                    .SelectionColor = .ForeColor
                End With
                strSText = oInFile.Readline
            End If
        Loop
        oInFile.Close()



Surely there's a better solution than this mess! I've attached a SAS log file like one I'd be reading in if anyone wants to give it a try (please note there are an enormous number of errors and warnings in the log file; I did that on purpose so I'd have a diverse log file to work with). I'd appreciate any insight you guys might have.

Attached File(s)

  • Attached File  Log.txt (20.91K)
    Number of downloads: 38


Is This A Good Question/Topic? 0
  • +

Replies To: There has to be a better way to do this...

#2 trichardson  Icon User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 9
  • Joined: 02-December 12

Re: There has to be a better way to do this...

Posted 27 December 2012 - 12:39 PM

Try creating a line type enum to determine what actions to take rather than having a whole subset of code for each value of strSText.

Something like this:

Outside of the function declare the Enum:
Enum LineType
        Err = 0
        Note = 1
        Warning = 2
        Other = 3
    End Enum



Within the function restructure your code like this:
oInFile = oInFileO.OpenTextFile(chrDrive & ":\SASH2\Log.log", IOMode.ForReading)

        strSText = ""
        Do While Not oInFile.AtEndOFStream
            Dim line_type As Integer
            Dim clColor As Color

            If strSText Like "ERROR:*" Then
                line_type = LineType.Err
                clColor = Color.Red
            ElseIf strSText Like "WARNING:*" Then
                line_type = LineType.Warning
                clColor = Color.Green
            ElseIf strSText Like "NOTE:*" Then
                line_type = LineType.Note
                clColor = Color.Blue
            Else
                line_type = LineType.Other
                clColor = Color.Black
            End If

            If line_type <> LineType.Other Then
                If line_type = LineType.Error Or line_type = LineType.Warning Then
                    aryErrors.Add(strSText)
                End If

                With frmSAS.txtLog
                    .Selectionstart = .TextLength
                    .SelectionColor = clColor
                    .AppendText(strSText & vbNewLine)
                    .SelectionColor = .ForeColor
                End With
                strSText = oInFile.Readline

                If line_type <> LineType.Other Then
                    If Len(strSText) > 5 Then
                        Do While strSText Like "    *" And Not oInFile.AtEndOFStream
                            With frmSAS.txtLog
                                .Selectionstart = .TextLength
                                .SelectionColor = clColor
                                .AppendText(strSText & vbNewLine)
                                .SelectionColor = .ForeColor
                            End With
                            strSText = oInFile.Readline
                        Loop
                    End If
                End If
            End If
        Loop
        oInFile.Close()


Was This Post Helpful? 0
  • +
  • -

#3 lucky3  Icon User is offline

  • Friend lucky3 As IHelpable
  • member icon

Reputation: 231
  • View blog
  • Posts: 765
  • Joined: 19-October 11

Re: There has to be a better way to do this...

Posted 27 December 2012 - 12:41 PM

I personally prefer Regex for text filtering, so I'd read whole file, and then get all lines that match NOTE with:
Dim noteMatches = Regex.Matches(incomingString, "NOTE.*") 'and you instantly have 72 matches from your example text



Then you can do whatever you like with those matches.
Was This Post Helpful? 0
  • +
  • -

#4 C.Andrews  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 169
  • Joined: 18-October 12

Re: There has to be a better way to do this...

Posted 27 December 2012 - 12:53 PM

View Posttrichardson, on 27 December 2012 - 12:39 PM, said:

Try creating a line type enum to determine what actions to take rather than having a whole subset of code for each value of strSText.


While I agree that this solution is a bit less convoluted, I have to say it's not much less convoluted. It does eliminate a lot of repetitious code, though, which is a big part of what bothers me about my solution.
Was This Post Helpful? 0
  • +
  • -

#5 C.Andrews  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 169
  • Joined: 18-October 12

Re: There has to be a better way to do this...

Posted 27 December 2012 - 12:59 PM

View Postlucky3, on 27 December 2012 - 12:41 PM, said:

I personally prefer Regex for text filtering, so I'd read whole file, and then get all lines that match NOTE with:
Dim noteMatches = Regex.Matches(incomingString, "NOTE.*") 'and you instantly have 72 matches from your example text



Then you can do whatever you like with those matches.


I like this idea in terms of simplicity, however, I feel like I'm going to run into a problem correctly coloring the indented lines that go with the error/warning messages using this technique. If I understand correctly, you're saying that once I've defined my criteria, I can just color each of the lines that match my conditions accordingly using the *condition*Matches arrays I've created?

So what about the indented lines following the warnings and errors? I can get a collection of indent-matches for those using the same technique, but I feel like I'm not going to be able to correlate them back to either an error or warning condition, and therefore won't know whether a given match needs to be green or red.
Was This Post Helpful? 0
  • +
  • -

#6 lucky3  Icon User is offline

  • Friend lucky3 As IHelpable
  • member icon

Reputation: 231
  • View blog
  • Posts: 765
  • Joined: 19-October 11

Re: There has to be a better way to do this...

Posted 27 December 2012 - 01:48 PM

Each match has Index and Length property. Sum them together, and you get indexes of match end. If tabbed match starts with match end index +1, you know where it belongs.
Was This Post Helpful? 0
  • +
  • -

#7 C.Andrews  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 169
  • Joined: 18-October 12

Re: There has to be a better way to do this...

Posted 27 December 2012 - 02:09 PM

View Postlucky3, on 27 December 2012 - 01:48 PM, said:

Each match has Index and Length property. Sum them together, and you get indexes of match end. If tabbed match starts with match end index +1, you know where it belongs.



Ah, very clever good sir. Now, riddle me this: What about the unfortunate circumstance that arises in the real world application of this function in which the number of indented lines following an error or warning varies between 0 and X, with no reliable predictor of how many additional lines may be present (some of these error messages are seriously huge)?

I'm thinking that I can just check the tabbed-match index against +1 to +X, however, I'm not sure How I'd resolve this:

 WARNING: Your code was bad...
	...and you should feel bad.
 ERROR: No, seriously, where did you learn to code?
 	...because... DAMN!



In the above case (entirely likely to appear in my real world case, in form if not definition), I have an single tabbed-match index that is equal to:

A. +1 of a warning match index
B. +3 of a warning match index
-AND-
C. +1 of an error match index

I suppose I could just use conditional logic to handle this case, but then I'd end up with a factorial problem relating to all the possibilities I'd have to handle (+1 to +X of case Note, Error, Warning, and combinations of the three), and then I'd be back to a huge messy crappy block of code again.

I really do appreciate your suggestions. I have a lot to learn and troubling through these possibilities is very helpful for me.

*EDIT
Duh. I can just stop looking for additional indented lines once I reach a line that isn't indented, since I know I've reached the end of the message, no matter how many lines it is long.

This post has been edited by C.Andrews: 27 December 2012 - 02:12 PM

Was This Post Helpful? 0
  • +
  • -

#8 trevster344  Icon User is offline

  • The Peasant
  • member icon

Reputation: 224
  • View blog
  • Posts: 1,507
  • Joined: 16-March 11

Re: There has to be a better way to do this...

Posted 27 December 2012 - 05:56 PM

While I don't mind Regex at all I don't think it's really necessary here. I'd be far more comfortable with a function, and a case statement.
Was This Post Helpful? 0
  • +
  • -

#9 C.Andrews  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 14
  • View blog
  • Posts: 169
  • Joined: 18-October 12

Re: There has to be a better way to do this...

Posted 28 December 2012 - 02:06 PM

I meant to get back to this sooner but our internet has been down all day a work. Ultimately, I ended up going with the following solution:

        Dim TextColor As Color
        Do While Not OInfile.AtEndOFStream
            If strSText Like "ERROR*" Then
                TextColor = Color.Red
                aryErrors.Add(strSText)
            ElseIf strSText Like "WARNING*" Then
                TextColor = Color.Green
                aryErrors.Add(strSText)
            ElseIf strSText Like "NOTE*" Then
                TextColor = Color.Blue
            ElseIf strSText Like "    *" And Len(strSText) > 5 Then
                'Do nothing (inherits color from previous)
            Else
                TextColor = Color.Black
            End If

            With Me.txtLog
                .Selectionstart = .TextLength
                .SelectionColor = TextColor
                .AppendText(strSText & vbNewLine)
                .SelectionColor = .ForeColor
            End With
            strSText = OInfile.Readline
        Loop



I feel this is an appropriately straightforward method, and saves about 67 lines of code over my original, clunky version. I tried working with a Regex solution, but I ended up feeling like it was pretty messing when I got into comparing arrays of matches to figure out which lines needed colored based on their indices.

*EDIT*
Double post.

This post has been edited by C.Andrews: 28 December 2012 - 02:07 PM

Was This Post Helpful? 1
  • +
  • -

Page 1 of 1