35

How is it possible to split a VBA string into an array of characters?

I tried Split(my_string, "") but this didn't work.

slugster
  • 49,403
  • 14
  • 95
  • 145
intrigued_66
  • 16,082
  • 51
  • 118
  • 189

7 Answers7

56

Safest & simplest is to just loop;

Dim buff() As String
ReDim buff(Len(my_string) - 1)
For i = 1 To Len(my_string)
    buff(i - 1) = Mid$(my_string, i, 1)
Next

If your guaranteed to use ansi characters only you can;

Dim buff() As String
buff = Split(StrConv(my_string, vbUnicode), Chr$(0))
ReDim Preserve buff(UBound(buff) - 1)
Alex K.
  • 171,639
  • 30
  • 264
  • 288
  • The latter method might not work if the current locale is not 1033 (it *might* work if there's only ASCII character, but even then "it's an ugly hack and should not be used") – user202729 Oct 05 '21 at 12:41
  • Trying both of these on a million character string, I found the first method was about 7 times faster. It was also faster than methods using split(): even just the line running split, once delimeters are in place, took longer on my testing. – Mark E. Feb 07 '22 at 05:28
17

You can just assign the string to a byte array (the reverse is also possible). The result is 2 numbers for each character, so Xmas converts to a byte array containing {88,0,109,0,97,0,115,0}
or you can use StrConv

Dim bytes() as Byte
bytes = StrConv("Xmas", vbFromUnicode)

which will give you {88,109,97,115} but in that case you cannot assign the byte array back to a string.
You can convert the numbers in the byte array back to characters using the Chr() function

Charles Williams
  • 23,121
  • 5
  • 38
  • 38
10

Here's another way to do it in VBA.

Function ConvertToArray(ByVal value As String)
    value = StrConv(value, vbUnicode)
    ConvertToArray = Split(Left(value, Len(value) - 1), vbNullChar)
End Function
Sub example()
    Dim originalString As String
    originalString = "hi there"
    Dim myArray() As String
    myArray = ConvertToArray(originalString)
End Sub
Daniel
  • 12,982
  • 3
  • 36
  • 60
  • Beware that, by default, arguments are passed `ByRef` in VBA. Your function will modify `value`!!! – iDevlop Dec 06 '18 at 08:47
  • 1
    @PatrickHonorez Thanks. I probably didn't know that at the time. – Daniel Dec 06 '18 at 15:06
  • 1
    Instead of using Split(Left(value, Len(value) - 1), vbNullChar), you can use Split(value, vbNullChar, Len(value)). A little cleaner, and less string manipulation. Still good code. – Tom Collins Mar 09 '19 at 23:54
  • @lukazoid: your link is related to vb, not vba – iDevlop Jul 12 '19 at 15:19
  • https://learn.microsoft.com/fr-fr/office/vba/language/reference/user-interface-help/function-statement – iDevlop Jul 12 '19 at 16:23
  • @PatrickHonorez Thanks, I didn't realise VBA and VB6 were different languages, what a mess! Removed my comment. – Lukazoid Jul 12 '19 at 23:59
  • @PatrickHonorez that is false. Strings are immutable. You can test this yourself by explicitly passing `ByRef`. It does not modify the original string. – SSlinky Mar 03 '21 at 02:16
  • @Sam V: If you pass a variable myString with value "dog" into a function as, say, "strArgument", and the body of the function consists solely of the line strArgument = "cat", you'll find after running the function that myString is now equal to "cat". I'm curious what you tested, if you found something else. – Mark E. Feb 20 '22 at 22:08
  • @MarkE. Well I'm happy to have been corrected! I didn't test is the short answer. Confidently incorrect. Perhaps I was confused by the behaviour in Python. – SSlinky Feb 23 '22 at 00:43
8

According to this code golfing solution by Gaffi, the following works:

a = Split(StrConv(s, 64), Chr(0))
q335r49
  • 608
  • 8
  • 10
  • 1
    This is neat and pretty fast but as the source notes it does leave an extra blank at the end of the array. – Mark E. Feb 07 '22 at 05:27
  • This should be the top solution, unless there are more drawbacks than the empty array slot... it works great on simple text. – Justin Doward Jun 24 '22 at 02:22
  • Good solution. Just declare `a` as a variant at the beginning and add the line `ReDim Preserve a(UBound(a) - 1)` after computing `a`. – Alper Oct 11 '22 at 08:15
0

the problem is that there is no built in method (or at least none of us could find one) to do this in vb. However, there is one to split a string on the spaces, so I just rebuild the string and added in spaces....

Private Function characterArray(ByVal my_string As String) As String()
  'create a temporary string to store a new string of the same characters with spaces
  Dim tempString As String = ""
  'cycle through the characters and rebuild my_string as a string with spaces 
  'and assign the result to tempString.  
  For Each c In my_string
     tempString &= c & " "
  Next
  'return return tempString as a character array.  
  Return tempString.Split()
End Function
user3738926
  • 1,178
  • 1
  • 10
  • 17
  • When you are already stepping through the string character by character, why would you not just build an array of those characters (as in the acceptd answer that had been around for 3 years before this post) instead of building another longer string, then having an internal function step through that string character-by-character to build the array? And guess what happens when my_string contains spaces. Besides which, the question was about VBA, not VB (`For Each c In my_string` does not work in VBA). Also VB has `my_string.ToCharacterArray()` – Paul Sinclair Feb 27 '19 at 16:39
0

To split a string into an array of sub-strings of any desired length:

Function charSplitMulti(s As Variant, splitLen As Long) As Variant
    
        Dim padding As Long: padding = 0
        Dim l As Long: l = 0
        Dim v As Variant
        
        'Pad the string so it divides evenly by
        ' the length of the desired sub-strings
        Do While Len(s) Mod splitLen > 0
            s = s & "x"
            padding = padding + 1
        Loop
        
        'Create an array with sufficient
        ' elements to hold all the sub-strings
        Do Until Len(v) = (Len(s) / splitLen) - 1
            v = v & ","
        Loop
        v = Split(v, ",")
        
        'Populate the array by repeatedly
        ' adding in the first [splitLen]
        ' characters of the string, then
        ' removing them from the string
        Do While Not s Like ""
            v(l) = Mid(s, 1, splitLen)
            s = Right(s, Len(s) - splitLen)
            l = l + 1
        Loop
        
        'Remove any padding characters added at step one
        v(UBound(v)) = Left(v(UBound(v)), Len(v(UBound(v))) - padding)
        
        'Output the array
        charSplitMulti = v
    
    End Function

You can pass the string into it either as a string:

Sub test_charSplitMulti_stringInput()

    Dim s As String: s = "123456789abc"
    Dim subStrLen As Long: subStrLen = 4
    Dim myArray As Variant
    
    myArray = charSplitMulti(s, subStrLen)
    
    For i = 0 To UBound(myArray)
        MsgBox myArray(i)
    Next

End Sub

…or already declard as a variant:

Sub test_charSplitMulti_variantInput()

    Dim s As Variant: s = "123456789abc"
    Dim subStrLen As Long: subStrLen = 5
    
    s = charSplitMulti(s, subStrLen)
    
    For i = 0 To UBound(s)
        MsgBox s(i)
    Next

End Sub

If the length of the desired sub-string doesn't divide equally into the length of the string, the uppermost element of the array will be shorter. (It'll be equal to strLength Mod subStrLength. Which is probably obvious.)

I found that most-often I use it to split a string into single characters, so I added another function, so I can be lazy and not have to pass two variables in that case:

Function charSplit(s As Variant) As Variant

    charSplit = charSplitMulti(s, 1)

End Function

Sub test_charSplit()

    Dim s As String: s = "123456789abc"
    Dim myArray As Variant
    
    myArray = charSplit(s)
    
    For i = 0 To UBound(myArray)
        MsgBox myArray(i)
    Next

End Sub
Daz
  • 1
  • 2
0

Try this minicode From Rara:

Function charSplitMulti(TheString As Variant, SplitLen As Long) As Variant
    'Defining a temporary array.
    Dim TmpArray() As String
    'Checking if the SplitLen is not less than one. if so the function returns the whole string without any changing.
    SplitLen = IIf(SplitLen >= 1, SplitLen, Len(TheString))
    'Redefining the temporary array as needed.
    ReDim TmpArray(Len(TheString) \ SplitLen + IIf(Len(TheString) Mod SplitLen <> 0, 1, 0))
    'Splitting the input string.
    For i = 1 To UBound(TmpArray)
        TmpArray(i) = Mid(TheString, (i - 1) * SplitLen + 1, SplitLen)
    Next
    'Outputing the result. 
    charSplitMulti = TmpArray
End Function
Rara
  • 1
  • 1
  • 1
    Congrats on your first answer!) But please check if your answer have any help or benefit, does it provide new algorithm? does it more optimal, or code more condensed? – 2oppin Dec 18 '21 at 08:07