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

Viewed 882

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?

3 Answers

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.

I would not recommend using the VB constants. Instead, you should be using the Environment.NewLine property: https://docs.microsoft.com/en-us/dotnet/api/system.environment.newline

Per the documentation:

The property value of NewLine is a constant customized specifically for the current platform and implementation of the .NET Framework.

Usage:

Dim myNames = My.Resources.TreeNames.Split(Environment.NewLine)

Of course, you could skip .Split altogether and just

Dim LinesList = File.ReadAllLines("txtFruit.txt").ToList

With Option Infer on hold your cursor over LinesList and you will see that it is a strongly typed List(Of String)

Related