Results 1 to 5 of 5

Thread: String Split Remove SOME Empty Entries

  1. #1

    Thread Starter
    Member G_Hosa_Phat's Avatar
    Join Date
    May 2008
    Location
    Oklahoma City, OK
    Posts
    44

    String Split Remove SOME Empty Entries

    I'm trying to create an extension method for wrapping text to a specific number of characters for display in a console application. For the most part, it works very well, but I've run into a slight issue with how it handles a string that contains line breaks (Environment.NewLine, vbCr, vbLf, vbCrLf). Here's the method I'm currently working with:
    vbnet Code:
    1. <Extension()>
    2.     Public Function Wrap(ByVal Text As String, ByVal Width As Integer, Optional ByVal FullWidthLine As Boolean = False) As String
    3.         Dim InputLines As List(Of String) = Text.Split(New Char() {vbCr, vbLf, vbCrLf, Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries).ToList
    4.         Dim OutputLines As New List(Of String)
    5.  
    6.         For Each Line As String In InputLines
    7.             Dim Words As List(Of String) = Line.Split(CChar(" ")).ToList()
    8.  
    9.             If Line.Length < Width OrElse Words.Count = 1 Then
    10.                 If FullWidthLine Then
    11.                     OutputLines.Add(Line.PadRight(Width, " "c))
    12.                 Else
    13.                     OutputLines.Add(Line)
    14.                 End If
    15.             Else
    16.                 Dim CurrentLine As String = Words(0)
    17.  
    18.                 For I As Integer = 1 To Words.Count - 1
    19.                     If (CurrentLine & " " & Words(I)).Length > Width Then
    20.                         If FullWidthLine Then
    21.                             OutputLines.Add(CurrentLine.PadRight(Width, " "c))
    22.                         Else
    23.                             OutputLines.Add(CurrentLine)
    24.                         End If
    25.  
    26.                         CurrentLine = Words(I)
    27.  
    28.                         If I = Words.Count - 1 Then
    29.                             If FullWidthLine Then
    30.                                 OutputLines.Add(CurrentLine.PadRight(Width, " "c))
    31.                             Else
    32.                                 OutputLines.Add(CurrentLine)
    33.                             End If
    34.                         End If
    35.                     Else
    36.                         If I = Words.Count - 1 Then
    37.                             If FullWidthLine Then
    38.                                 OutputLines.Add((CurrentLine & " " & Words(I)).PadRight(Width, " "c))
    39.                             Else
    40.                                 OutputLines.Add(CurrentLine & " " & Words(I))
    41.                             End If
    42.                         End If
    43.  
    44.                         CurrentLine &= " " & Words(I)
    45.                     End If
    46.                 Next I
    47.             End If
    48.         Next
    49.  
    50.         Return String.Join(Environment.NewLine, OutputLines.ToArray())
    51.     End Function

    For a string like $"Invalid selection. Option {UserInput} is not available." & vbCrLf & "Please enter the number of the desired menu item from the list below." This works exactly as expected. The output is "wrapped" to two lines and displayed pretty much exactly as it was entered:

    Code:
    Invalid selection. Option 9 is not available.
    Please enter the number of the desired menu item from the list below.
    However, if I want to add an additional line of space between the two lines like this: $"Invalid selection. Option {UserInput} is not available." & vbCrLf & vbCrLf & "Please enter the number of the desired menu item from the list below." the StringSplitOptions.RemoveEmptyEntries wipes out my "extra" line and I end up with exactly the same thing as before:

    Code:
    Invalid selection. Option 9 is not available.
    Please enter the number of the desired menu item from the list below.
    Now, this is to be expected because the extra line break is "technically" an empty entry. But, in this case, I actually want that extra bit of space between the two lines.

    Code:
    Invalid selection. Option 9 is not available.
    
    Please enter the number of the desired menu item from the list below.
    If I remove the StringSplitOptions.RemoveEmptyEntries parameter from my Split method call (or change it to StringSplitOptions.None), then I end up with additional empty lines in my OutputLines List(Of String) object that "don't belong" there.

    So, now I'm just trying to figure out how to build my List(Of String) object, split on any of the new line character(s), preserving blank lines, but not "creating" empty entries.

    In my testing, I've tried to do this:
    vbnet Code:
    1. Dim NewLines As Char() = {vbCrLf, vbCr, vbLf, Environment.NewLine}
    2.         Dim TestLines As New List(Of String)
    3.         Dim LastIndex As Integer = 0
    4.         Dim NextIndex As Integer = Text.IndexOfAny(NewLines, LastIndex)
    5.  
    6.         Do While NextIndex > 0
    7.             TestLines.Add(Text.Substring(LastIndex, NextIndex))
    8.             LastIndex = NextIndex + 1
    9.             NextIndex = Text.IndexOfAny(NewLines, LastIndex)
    10.         Loop
    But, that ends up creating "duplicate" lines in my list because it's hitting each of the individual new line characters - vbCr (Chr(13)) and vbLf (Chr(10)) - and creating a new line for that. I tried just using Environment.NewLine or vbCrLf, but those don't seem to catch things correctly either and I end up with just two lines - everything up to the first line break, then one for everything after the new line characters at the beginning. It's still not what I'm after and I'm just not sure how to get there. Any assistance would be greatly appreciated.
    Last edited by G_Hosa_Phat; May 18th, 2022 at 12:13 PM.

  2. #2
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: String Split Remove SOME Empty Entries

    So, if I'm reading right... sometimes you want to remove the empty lines ... other times not ... Would an optional flag PreserveEmpty work? Default to false. False would include the RemoveemptyEntries, while True wouldn't.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  3. #3

    Thread Starter
    Member G_Hosa_Phat's Avatar
    Join Date
    May 2008
    Location
    Oklahoma City, OK
    Posts
    44

    Re: String Split Remove SOME Empty Entries

    Sorta, but sorta not. Let me see if I can explain it a bit better:

    Here's the string I'm testing with:

    $"Invalid selection. Option {UserInput} is not available." & vbCrLf & vbCrLf & "Please enter the number of the desired menu item from the list below."

    Using the String.Split() method with the StringSplitOptions.None option, I get the following five entries added to my list:

    [0] "Invalid selection. Option 9 is not available."
    [1] ""
    [2] ""
    [3] ""
    [4] "Please enter the number of the desired menu item from the list below."

    With the StringSplitOptions.RemoveEmptyEntries option, I get just two entries added to the list:

    [0] "Invalid selection. Option 9 is not available."
    [1] "Please enter the number of the desired menu item from the list below."

    What I WANT is three entries in the list like this:

    [0] "Invalid selection. Option 9 is not available."
    [1] ""
    [2] "Please enter the number of the desired menu item from the list below."

    Does that help clarify what I'm trying to accomplish?

    ADDITIONAL TESTING:
    I almost thought I had the solution by using Regex.Split() instead of String.Split():
    Code:
    Dim InputLines As List(Of String) = System.Text.RegularExpressions.Regex.Split(Text, vbCrLf).ToList
    This worked great for my original testing string above, but it "failed" when I changed the vbCrLf characters to just vbLf. Because I don't want it to break apart the vbCrLf into two separate new line characters but I still want it to split on any individual new line characters, I guess I need to find a way to "normalize" the line breaks so the Split() method (whichever one works best in this case) can pick them up properly. Unless there's a way to "prioritize" the separators in a split operation so it looks for the vbCrLf before trying to find either the vbLf or vbCr.

    Of course, now that I'm thinking of it, I suppose I could do it in two passes: the first pass splits on the vbCrLf, then it goes through each of those lines and splits them on either the vbCr or vbLf...
    Last edited by G_Hosa_Phat; May 18th, 2022 at 12:52 PM.

  4. #4
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: String Split Remove SOME Empty Entries

    How often will you have a CR or LF that's not a CRLF?

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  5. #5

    Thread Starter
    Member G_Hosa_Phat's Avatar
    Join Date
    May 2008
    Location
    Oklahoma City, OK
    Posts
    44

    Re: String Split Remove SOME Empty Entries

    If I'm writing the code, virtually never. But, I'm trying to build this as an extension in a library that might be used by someone else or might be taking input from a source (like a file or something) where I can't necessarily control what line break characters are coming in.

    But... I think I've found a solution. It's a little "wonky", but it seems to work for the situation. I'm "normalizing" the input text by converting all new line characters to vbLf:
    Code:
    Dim NormalizedText As String = Text.Replace(vbCrLf, vbLf).Replace(vbCr, vbLf)
    This way, I don't have to worry about it breaking up a vbCrLf and creating "extra" entries. Once the text is "normalized", I then use the Regex.Split() method from above to split it on the vbLf character only, and voilà, I have three entries in my list!
    Code:
    Dim InputLines As List(Of String) = System.Text.RegularExpressions.Regex.Split(NormalizedText, vbLf).ToList
    Even if I change the testing string to use a combination of vbCrLf, vbLf, or vbCr, it seems to finally be doing what I was trying to achieve!

    So, here's what I've come up with:
    vbnet Code:
    1. <Extension()>
    2. Public Function Wrap(ByVal Text As String, ByVal Width As Integer, Optional ByVal FullWidthLine As Boolean = False) As String
    3.     Dim NormalizedText As String = Text.Replace(vbCrLf, vbLf).Replace(vbCr, vbLf)
    4.     Dim InputLines As List(Of String) = System.Text.RegularExpressions.Regex.Split(NormalizedText, vbLf).ToList
    5.     Dim OutputLines As New List(Of String)
    6.  
    7.     For Each Line As String In InputLines
    8.         Dim Words As List(Of String) = Line.Split(CChar(" ")).ToList()
    9.  
    10.         If Line.Length < Width OrElse Words.Count = 1 Then
    11.             If FullWidthLine Then
    12.                 OutputLines.Add(Line.PadRight(Width, " "c))
    13.             Else
    14.                 OutputLines.Add(Line)
    15.             End If
    16.         Else
    17.             Dim CurrentLine As String = Words(0)
    18.  
    19.             For I As Integer = 1 To Words.Count - 1
    20.                 If (CurrentLine & " " & Words(I)).Length > Width Then
    21.                     If FullWidthLine Then
    22.                         OutputLines.Add(CurrentLine.PadRight(Width, " "c))
    23.                     Else
    24.                         OutputLines.Add(CurrentLine)
    25.                     End If
    26.  
    27.                     CurrentLine = Words(I)
    28.  
    29.                     If I = Words.Count - 1 Then
    30.                         If FullWidthLine Then
    31.                             OutputLines.Add(CurrentLine.PadRight(Width, " "c))
    32.                         Else
    33.                             OutputLines.Add(CurrentLine)
    34.                         End If
    35.                     End If
    36.                 Else
    37.                     If I = Words.Count - 1 Then
    38.                         If FullWidthLine Then
    39.                             OutputLines.Add((CurrentLine & " " & Words(I)).PadRight(Width, " "c))
    40.                         Else
    41.                             OutputLines.Add(CurrentLine & " " & Words(I))
    42.                         End If
    43.                     End If
    44.  
    45.                     CurrentLine &= " " & Words(I)
    46.                 End If
    47.             Next I
    48.         End If
    49.     Next
    50.  
    51.     Return String.Join(Environment.NewLine, OutputLines.ToArray())
    52. End Function
    I suppose I just needed to talk it out a bit.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width