String length when converting from a character array

后端 未结 4 655
耶瑟儿~
耶瑟儿~ 2020-12-06 20:08

I\'m having serious problems with string-handling. As my problems are rather hard to describe, I will start with some demo code reproducing them:

Dim s1 As S         


        
相关标签:
4条回答
  • 2020-12-06 21:01

    I changed the variable names for clarity:

    Dim myChars(30) As Char
    myChars(0) = "h"c           ' cannot convert string to char
    myChars(1) = "i"c           ' under option strict (narrowing)
    Dim myStrA As New String(myChars)
    Dim myStrB As String = CStr(myChars)
    

    The short answer is this:

    Under the hood, strings are character arrays. The last 2 lines both create a string one using NET code, the other a VB function. The thing is that, although the array has 31 elements, only 2 were initialized:

    The rest are null/Nothing, which for a Char means Chr(0) or NUL. Since NUL is used to mark the end of a String, only the characters up to that NUL will print in the Console, MessageBox etc. Text appended to the string will not display either.


    Concepts

    Since the strings above are created directly from a char array, the length is that of the original array. The Nul is a valid char so they get added to the string:

    Console.WriteLine(myStrA.Length)     ' == 31
    

    So, why doesn't Trim remove the nul characters? MSDN (and Intellisense) tells us:

    [Trim] Removes all leading and trailing white-space characters from the current String object.

    The trailing null/Chr(0) characters are not white-space like Tab, Lf, Cr or Space, but is a control character.

    However, String.Trim has an overload which allows you to specify the characters to remove:

    myStrA = myStrA.Trim(Convert.ToChar(0))
    ' using VB namespace constant
    myStrA = myStrA.Trim( Microsoft.VisualBasic.ControlChars.NullChar)
    

    You can specify multiple chars:

    ' nuls and spaces:
    myStrA = myStrA.Trim(Convert.ToChar(0), " "c)
    

    Strings can be indexed / iterated as a char array:

        For n As Int32 = 0 To myStrA.Length
            Console.Write("{0} is '{1}'", n, myStrA(n))  ' or myStrA.Chars(n)
        Next
    

    0 is 'h'
    1 is 'i'
    2 is '

    (The output window will not even print the trailing CRLF.) You cannot change the string's char array to change the string data however:

       myStrA(2) = "!"c
    

    This will not compile because they are read-only.

    See also:

    ASCII table

    0 讨论(0)
  • 2020-12-06 21:06

    If you want to create strings from a byte array, i.e. ID3v2.4.0 with ISO-8859 encoding, then this should work:

        Dim s1 As String = "Test"
        Dim b() As Byte = New Byte() {84, 101, 115, 116, 0, 0, 0}
        Dim s2 As String = System.Text.ASCIIEncoding.ASCII.GetString(b).Trim(ControlChars.NullChar)
    
        If s1 = s2 Then Stop
    

    According to this http://id3.org/id3v2.4.0-structure other encodings may be present and the code would need to be adjusted if one of the others is used.

    0 讨论(0)
  • 2020-12-06 21:07

    You can either Dim or ReDim the char array once you know the length of the s1 string.

    Dim s1 As String
    s1 = "hi"
    Dim c(s1.Length) As Char
    c(0) = "h"
    c(1) = "i"
    Dim s2 As String = CStr(c)
    

    And now your comparison will work no matter the length of the original string. You didn't state whether the length of 30 for 'c' is a requirement or not here.

    But even if it was, you'd still need to either expand or contract the array to have the same CStr length to do your comparison.

    So even after declaring

    Dim c(30)
    

    You can later in the code block redimension the array like this

    ReDim c(s1.Length) 'Or any int value you like
    

    If increasing you can precede with the preserve keyword, which will expand the array while maintaining its current contents.

    ReDim Preserve c(s1.Length)
    
    0 讨论(0)
  • 2020-12-06 21:09

    The cause is that CStr(c) is treating the NUL (0) characters as members of the resulting string instead of a string-terminator. The base String.Trim() fails to work because it does not consider NUL characters as white-space.

    One way to avoid this problem is to only convert the characters (or bytes) up to the first NUL (or 0); the TakeWhile function is useful in this case.

    Const NUL as Char = Microsoft.VisualBasic.ChrW(0)
    Dim cleanChars() as Char = _
        c.TakeWhile(Function(v, i) v <> NUL) _
         .ToArray
    
    CStr(cleanChars) ' -> "hi"
    

    If the data really comes from Bytes (and not Chars), it might be prudent to switch to Encoding.GetString so the encoding/process is explicit and well-understood, e.g.

    Encoding.UTF8.GetString(cleanBytes) ' -> still "hi"
    
    0 讨论(0)
提交回复
热议问题