Search code examples
vb.netwinformssplitcarriage-returnlinefeed

String.Split() using VbCrLf doesn't work but replacing VbCr with "" first then splitting on VbLf does work. Why?


I have an embedded text file as a Resource. The content is:

Apple
Pear
Orange

I am trying to pull this into a List(Of String) but the Carriage Return and Line Feed characters are messing it up.
For example I try this:

Dim myNames As List(Of String) = My.Resources.TreeNames.Split(CChar(vbCrLf)).ToList

But the line feed character is being passed through:

"Apple"
vbLf & "Pear"
vbLf & "Orange"

so I try it using the environment variable:

Dim myNames As List(Of String) = My.Resources.TreeNames.Split(CChar(Environment.NewLine)).ToList

But that results in the exact same output.
So I try splitting it on the line feed character:

Dim myNames As List(Of String) = My.Resources.TreeNames.Split(CChar(vbLf)).ToList

And now the carriage return character is being passed through:

"Apple" & vbCr
"Pear" & vbCr
"Orange"

So the only way I got this to work is by first replacing the vbCr with nothing then splitting on the left over vbLf:

Dim myNames As List(Of String) = Replace(My.Resources.TreeNames, vbCr, "").Split(CChar(vbLf)).ToList

Can anyone explain why? If I pull the file in directly to a string using this:

Dim myNames as String = My.Resources.TreeNames

I get:

"Apple" & vbCrLf & "Pear" & vbCrLf & "Orange"

Why is split not working properly?


Solution

  • See the Docs about CChar(<expression>):

    Any valid Char or String expression; only first character of a String is converted; value can be 0 through 65535 (unsigned)

    So CChar(vbCrLf) returns just VbCr (\r - &H0D)

    Since you're now splitting the source string on just VbCr, the Line Feed, VbLf (\n - &H0A), remains.

    You need the overload of String.Split() that accepts an array of Strings or Chars:
    Note that vbCrLf is a String Type, so are VbCr and VbLf

    Dim res = My.Resources.TreeNames
    ' As an array of String
    Dim myNames = res.Split({vbCrLf}, StringSplitOptions.RemoveEmptyEntries).ToList()
    'Or
    Dim myNames = res.Split({vbCr, VbLf}, StringSplitOptions.RemoveEmptyEntries).ToList()
    

    Or as an array of Chars:

    Dim myNames = res.Split(vbCrLf.ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList()
    ' Or
    Dim myNames = res.Split({ChrW(13), ChrW(10)}, StringSplitOptions.RemoveEmptyEntries).ToList()
    

    StringSplitOptions.RemoveEmptyEntries is used to remove empty lines generated by splitting on multiple contiguous chars.
    Without it, using your sample string - 3 items separated by Carriage Return + Line Feed - you would get an array of 5 elements instead of 3, including 2 empty elements.