Can you use split-function recursively on an split-item in VBA? - excel

I am struggling with the split function in VBA. Maybe I did something wrong with the declarations despite trying to switch around with Dim as Variant and Dim as String.
My code looks as following:
'Split the txtString variable at every "|" and add every split string item to an array split_sText
Dim txtString as String
.
.
.
Dim split_sText() As String
split_sText() = Split(txtString, "|")
Pick the first part of respective item out of that array and place it at the right cell
Sheets(Table1).Cells(1, 1) = Split(split_sText(15), "_")'
split_sText(15) looks like this: "ABC_1234". Of that string I only want to get the "ABC".
The error occurs at the last line because of "runtime error 13 not matching types", which is strange, since I've declared the variables as strings.
Thank you for your help!

I believe you are looking at the wrong place for your error.
Sheets(Table1) is the source of the error.
The Index argument for the Sheets object needs to be either a number, or a sheet name. Most likely, Table1 is the CodeName. The CodeName of an object returns the actual object.
So if Table1 is the CodeName, then change to
Table1.Cells(1,1) = ...
If Table1 happened to be the worksheet name, then it would be
Sheets("Table1").Cells(1,1) = ...
If you look at the Project Explorer window in the VBE, under the Microsoft Excel Objects for your project you will see one or more worksheet objects. The CodeName is the first name of the worksheet; the worksheet Name is the name in parentheses.
There are other issues with how you are splitting the string, but your code should work with a proper Sheets reference.

Dim Sp() As String declares an array of string type with an undefined number of elements.
Sp = Split("a_b_c_", "_") assigns an array to the variable already declared, defining also the number of elements, 0-based.
Debug.Print Sp(2) prints the 3rd element to the Immediate Pane.
Cells(1, 1).Value = Sp(2) assigns the same value to a cell.
The Split function returns an array of string type. However, the following will also work.
Dim Sp As Variant
Sp = Split("a_b_c_", "_")
Cells(1, 1).Value = Sp(2)
Observe that the variant is not declared as an array because the variant c an be anything by nature. Dim Sp() As Variant will cause Sp = Split("a_b_c_", "_") to fail.
As one final twist, you can also avoid the use of Sp with the code below.
Cells(1, 1).Value = Split("a_b_c_", "_")(2)

split_sText(15) looks like this: "ABC_1234". Of that string I only want to get the "ABC".
If there's one under score then there'd be a two item array, and you can only assign one array item to a cell:
Dim split_sText() As String
split_sText() = Split(txtString, "|")
Dim split_sTextNested() As String
split_sTextNested = Split(split_sText(15), "_")
Sheets(Table1).Cells(1, 1) = split_sTextNested(0)

Related

Concatenate values of more cells in a single variable in vba

I have an excel file with four columns: name, surname, address, area.
There are a lot of rows.
Is there a way to concatenate all the values of every single row in a variable, using vba?
I need a variable that should contain something like this:
(name1, surname1, address1, area1); (name2, surname2, address2, area2); (name3, surname3, address3, area3)...
If you have the following data in your worksheet
Then the following code will read the data into an array …
Option Explicit
Public Sub Example()
Dim RangeData() As Variant ' declare an array
RangeData = Range("A1:D5").Value2 ' read data into array
End Sub
… with the following structure:
Alternatively you can do something like
Public Sub Example()
Dim DataRange As Range
Set DataRange = Range("A2:D5")
Dim RetVal As String
Dim Row As Range
For Each Row In DataRange.Rows
RetVal = RetVal & "(" & Join(Application.Transpose(Application.Transpose(Row.Value2)), ",") & "); "
Next Row
Debug.Print RetVal
End Sub
To get this output:
(name1, surname1, address1, area1); (name2, surname2, address2, area2); (name3, surname3, address3, area3); (name4, surname4, address4, area4);
.. is there a way to write the result like a sort of list that shows all the values of the cells of the range?
Yes, there is. In addition to PEH's valid answers and disposing of Excel version MS365 you might also use
Dim s as String
s = Evaluate("ArrayToText(A2:D5, 1)") ' arg. value 1 representing strict format
resulting in the following output string:
{"name1","surname1","address1","area1";"name2","surname2","address2","area2";"name3","surname3","address3","area3";"name4","surname4","address4","area4"}
Syntax
ARRAYTOTEXT(array, [format])
The ARRAYTOTEXT function returns an array of text values from any specified range. It passes text values unchanged, and converts non-text values to text.
The format argument has two values, 0 (concise default format) and 1 (strict format to be used here to distinguish different rows, too):
Strict format, i.e. value 1 includes escape characters and row delimiters. Generates a string that can be parsed when entered into the formula bar. Encapsulates returned strings in quotes except for Booleans, Numbers and Errors.
Thank you for your answers, suggestions, ideas and hints. I am sorry if my question was not so clear, all the solutions you added were perfect and extremely elegant.
In the end I found a way - a dumber way in comparison to all the things you wrote - and I solved with a for statement.
I did like this:
totRow = ActiveSheet.UsedRange.Rows.Count
For i = 1 To totRow
name = Cells(i, 1)
surname = Cells(i, 2)
address = Cells(i, 3)
area = Cells(i, 4)
Example = Example & "(" & name & ", " & surname & ", " & address & ", " & area & "); "
Next i
Range("E1").Value = Example
It works (it does what I wanted to do), but I noticed a little limit: if the rows are a lot I can't keep the whole text in the variable.

How does excel interpret an array

Is an array stored as a string ?
Example :
Arr[0]="A"
Arr[1]="B"
Arr[2]="C"
Is this array stored like this "A,B,C" if yes, it is "," or ";" separator ?
I've built the following function :
Function test(Ref As String) As Variant
Dim creationdetableau() As String
Dim cpt As Integer
cpt = 0
For i = 1 To 35500
If Ref = ThisWorkbook.Worksheets("CashFlows").Cells(i, "A").Value Then
ReDim Preserve creationdetableau(cpt)
creationdetableau(cpt) = ThisWorkbook.Worksheets("CashFlows").Cells(i, "B").Value
cpt = cpt + 1
Debug.Print i
End If
Next i
test = creationdetableau
End Function
If I call
=test(A2)
In an excel sheet, would it print the string in ? If No how would you do ?
What Am I trying to do :
I try to use this formula
=CfDur(E2;P2;CashFlows!B2:B100;CashFlows!J2:J100)
But my goal is to replace this CashFlows!B2:B100 by a custom vba function called test
=CfDur(E2;P2;test(A2);CashFlows!J2:J100)
CashFlows!B2:B100 contains date :
to conclude :
=CfDur(E2;P2;test(A2);CashFlows!J2:J100)
does not work
They are not "stored" as a String, but as distinct elements that can be indexed or retrieved by iteration. For example:
Sub Dorian()
Dim Arr(0 To 2) As String, i As Long
Arr(0) = "A"
Arr(1) = "B"
Arr(2) = "C"
For i = 0 To 2
MsgBox Arr(i)
Next i
For Each a In Arr
MsgBox a
Next a
End Sub
NOTE:
The elements of an array can be numbers or Pictures or Ranges or most other types of Objects.
The receiving function will read the passed variable according to the data type of the array used to pass it:
Dim arrInt() as Integer
Dim arrStr() As String
Note: Dim arrVar as Variant and Dim arrVar() as Variant will yield the same result.
The built in Array method expects variant data.
A variant parameter will accept almost any data type passed to it, provided it can be parsed, so for max compatibility you could use variant in your function parameters.
For performance or safety use specific data types instead and ensure the arrays used are of the appropriate type.
You can make an array from all basic data types and many object types too. If you can't find an array type to suit use System.Collections.ArrayList,

Excel VBA: Is there a dynamic Array that can be used for Dates?

I'm working on an Excel Macro and I want to create an array of dates and then loop through it, without knowing how many dates will be added. I thought this would be simple, but I can't get it to work.
I tried using a collection:
Dim DateArr As Collection
Dim d As Date
Set DateArr = New Collection
DateArr.Add (CDate("1/1/2019"))
DateArr.Add (CDate("2/2/2020"))
For Each d In DateArr
sh.Cells(y, 27).Value = d
Next d
But I get an error that says "For Each control variable must be Variant or Object" and highlights the d in my loop. Are dates not objects?
I also tried a Variant:
Dim DateArr As Variant
DateArr.Add CDate("2/2/2020")
DateArr(1) = CDate("1/1/2019")
But I can't find the right syntax for adding a Date. The .Add line gives me an "Object Required" error and the DateArr(1)= line gives me a "Type Mismatch" error.
The only thing that kind of works is a standard array:
Dim DateArr() As Date
Dim y As Integer
ReDim DateArr(1 To 2) As Date
DateArr(1) = CDate("1/1/2019")
DateArr(2) = CDate("2/2/2020")
For y = LBound(DateArr) To UBound(DateArr)
sh.Cells(y, 27).Value = DateArr(y)
Next y
But I have no idea how many dates will be in the array, so can't use anything static. Is there a way to use this same syntax without setting dimensions?
Thanks!
Dates are variants not objects
Add for collections is a method. In your code you have assumed it is a function and added unnecessary parentheses, e.g.
DateArr.add cdate("1/1/2019")
To use a For Each then the indexing (controlling) variable must be an object or a variant.
Thus your first example should work fine (other errors not withstanding) if you dim d as a variant.

How to reference a collection in a formula

All I want to do is reference a collection in a formula. Like
Assume I already know how to make collections and arrays and have done so in my macro, Collection is literally a collection with only 1 column, and Textstring is an array vector.
'For every value of i in Textstring, I want to count the occurrence of that value in all the values of 'Collection'
For i = 1 to Whatever
=COUNTIF(Collection, """ & TextString(i) & """)
Next i
What I want to know is how to make aforementioned code work.
It should work like a normal countif:
'ie: "=COUNTIF('Sheet1'!A1:A10, ""blah"")"
You can't with COUNTIF, if you have a look at the arguments to the function, it expects a Range object.
The only suggestion I have is to do something like the below, i.e. write it out to a worksheet and then use that range as a parameter to your function ...
Public Sub CollectionToRange()
Dim objCollection As New Collection, i As Long
For i = 1 To 10
objCollection.Add i
Next
' Convert the collection to a range.
For i = 1 To objCollection.Count
Sheet1.Cells(i, 1) = objCollection.Item(i)
Next
' Pass the range into the worksheet function.
Debug.Print "CountIf Result = " & WorksheetFunction.CountIf(Sheet1.Range("A1:A" & objCollection.Count), ">3")
' Perform a clean up if required.
End Sub
Not sure if that helps or not.

excel vba: using string to set slicer doesn't work

I'm trying to set the slicer for a pivot table based on values I collected earlier in a string.
The code below works:
ActiveWorkbook.SlicerCaches("Slicer_Merk1").VisibleSlicerItemsList = Array( _
"[dXref].[Merk].&[J17]", "[dXref].[Merk].&[J18]")
However, instead of having two values like J17 and J18, I could have an unknown amount of them. So the code could also be:
ActiveWorkbook.SlicerCaches("Slicer_Merk1").VisibleSlicerItemsList = Array( _
"[dXref].[Merk].&[J17]", "[dXref].[Merk].&[J18]", "[dXref].[Merk].&[J50]", "[dXref].[Merk].&[J500]")
To solve this, in earlier code I collect whatever values I want to filter and I put them together in a string called "txt".
So the string "txt" could contain this:
"[dXref].[Merk].&[J17]", "[dXref].[Merk].&[J18]"
or
"[dXref].[Merk].&[J17]", "[dXref].[Merk].&[J18]", "[dXref].[Merk].&[J50]", "[dXref].[Merk].&[J500]"
Then I assumed this would work:
ActiveWorkbook.SlicerCaches("Slicer_Merk1").VisibleSlicerItemsList = Array( _
txt)
I thought that replacing the code that normally works to set the slicer with a variable containing the same code would work. However I keep getting error messages that give a clue that there is something wrong with the comma in the txt string when setting the slicer.
I have been searching online for hours and trying endless things. I might be missing something simple.... can someone figure this out? Thanks a lot.
The full sub below (which is now working):
Sub FiltersMatchen()
Dim Selectie As Range
Dim FilterArray() As String
Dim FilterString As String
Dim i As Long
Dim Merk As Range
Dim FiltercodeBegin As String
Dim FiltercodeEinde As String
Set Selectie = Selection
i = 0
ReDim FilterArray(0)
For Each Merk In Selectie
FilterArray(i) = Merk
i = i + 1
ReDim Preserve FilterArray(i)
Next
FiltercodeBegin = "[dXref].[Merk].&["
FiltercodeEinde = "]"
For i = LBound(FilterArray) To UBound(FilterArray) - 1
FilterString = FilterString & FiltercodeBegin & FilterArray(i) & FiltercodeEinde & Chr(44)
Next i
FilterString = Left(FilterString, Len(FilterString) - 1)
FilterArray = Split(FilterString, ",")
ActiveWorkbook.SlicerCaches("Slicer_Merk1").VisibleSlicerItemsList = FilterArray
End Sub
The answer is that I had to split the string into an array, and the individual items in the array don't need to have the " " characters around them while preparing those items. I assumed they were required because if you manually fill in the array (what you see when you record the a macro) they are there.
So, manually an array item looks like this:
"[dXref].[Merk].&[J17]"
Using an array, an item looks like this:
[dXref].[Merk].&[J17
I edited the start post with the solution. The sub is used to apply a selection of the pivot table to the slicer connected to that pivot table.

Resources