VBA function fails when inserting values into Array - arrays

I'm totally stumped on why this isn't returning a value. This set of functions is supposed to return the SUM of all the ASCII values in a String. The String and Number arrays build properly and the SUM function works on the Array, however when it tries to assign that summed value to the return variable, it fails.
By "it fails" I mean that the code does not step to the sum line and the function returns #VALUE! to the worksheet. Everything else checks out in the immediate window and steps through properly until the last line. Any suggestions are appreciated.
Private Function StringToCharArray(ByRef sIn As String) As String()
StringToCharArray = Split(StrConv(sIn, vbUnicode), Chr(0))
'provided by Fencliff at http://www.mrexcel.com/forum/excel-questions/342725-split-string-into-array.html
End Function
Function StringToNumber(MyString As String) As Integer
Dim StringArray() As String
Dim NumberArray() As Long
StringArray() = StringToCharArray(MyString)
ReDim NumberArray(UBound(StringArray))
For i = LBound(StringArray) To UBound(StringArray)
NumberArray(i) = Asc(StringArray(i))
Next i
StringToNumber = Application.WorksheetFunction.Sum(NumberArray)
End Function

Using an example of "abc" the Split obtains an array "a", "b", "c", "". That is, with an empty string element at the end. This cannot be converted to an ascii number so causes the error.
A simplistic solution is to skip this last element:
For i = LBound(StringArray) To UBound(StringArray) - 1
I suspect the problem (the extra element) is related to the use of Unicode but I haven't investigated this.

Related

VBA, How to pass in a string argument, convert to single character array and resize according to non-numerical values?

Ok,
To all those who may come across this question, this is a problem I have been banging my head against for the past two weeks and have made little or no progress, so any help would be extremely welcome.
Here's the set up; then I will follow with an excerpt of the code I have written:
I am writing a function to get a very specific formula for each file name in a given folder. This naturally requires me to write a program which can take string arguments (in this case, excel file names) from a very broad domain of possibilities and yield a very specific output based on some key -and highly unique- parameters. Hence, my function is bijective and the set of arguments and set of products are massive; therefore, I am in the process of writing a sub-process for this function which partitions the string argument, by character, into a corresponding array, remove all the unnecessary characters, concatenate the remaining characters into the output string, and then go through a series of checks to enforce whatever name-formula the file requires. For now, I am just focused on splitting the string into an array, removing all non-numeric characters and combining the remaining characters back into a single string.
Naturally, I have tried the split function, but to my knowledge VBA doesn't support the splitting of a string into single characters. So I have written the following code, which, admittedly, is a bit inelegant, but I think in principle must work. -It does not. Would someone kindly tell me why it doesn't, and make a recommendation for altering it.
Dim arr() As Variant
For i = Len(strArg) To i = 1
If IsNumeric(Mid$(strArg, i, 1)) = True Then
arr(i - 1) = Mid$(strArg, i, 1)
Else: arr(i - 1) = ""
End If
Next
newStr = Join(arr())
arr() always returns empty, so newStr is always "". Yet there are always numeric values in each string argument. -I can't imagine why I am getting this result. If I use ReDim arr(Len(strArg)), I get Len(strArg) number of " " back....
Thanks in advance to whomever may provide help.
Not sure why you need to split it into an array for this. Your description says you only want to have numeric characters returned in a new string variable. A function like this should work for you:
Function GetNumbers(ByVal arg_sText As String) As String
Dim i As Long
Dim sChar As String
Dim sNumbers As String
For i = 1 To Len(arg_sText)
sChar = Mid(arg_sText, i, 1)
If IsNumeric(sChar) Then sNumbers = sNumbers & sChar
Next i
GetNumbers = sNumbers
End Function
Then just call it in your code like this:
newStr = GetNumbers(strArg) 'Example: "ab1c2d" = "12"
Alternatively use a Regular Expression
Function NumOnly(s As String) As String
With CreateObject("VBScript.RegExp")
.Global = True
.MultiLine = False
.IgnoreCase = True
.Pattern = "[^0-9]+"
NumOnly = .Replace(s, "")
End With
End Function
As a further approach to the existing solutions, I'd like to demonstrate how to use the â–ºFilterXML() function and to check valid results.
The proposed function NumsOnly() consists only of three steps:
a) execute an XPath search upon xml content which has been created by getXML()
b) check valid results via procedure check
c) return the function result as new formed string
Coming close to the requirements in OP this includes also a way to
convert a string to a single character array (c.f. #JNevill 's comment to OP) and
to build a well-formed xml string as base for Filter.XML (see function getXML()) .
Main function NumsOnly()
Function NumsOnly(ByVal s As String) As String
'Purp: recognizes only numeric values in comparisons
'Note: no findings and single digit results are handled by proc check
Const xpath As String = "//*[.>0]" ' get only digits out of atomized characters
'a) execute XPath search upon xml content
Dim x: x = Application.FilterXML(getXML(s), xpath)
'b) check valid results
check x
'c) return only-nums string as function result
NumsOnly = x
End Function
Helper function getXML()
Extended udf based on Split string into array of characters?
Function getXML(ByVal s As String)
'Purp: return well-formed xml content string as base for FilterXML function
'1) atomize string elements into array
Dim buff() As String: buff = Split(StrConv(s, vbUnicode), Chr$(0))
ReDim Preserve buff(UBound(buff) - 1)
'2) return valid xml content string
getXML = "<ch><c>" & Join(buff, "</c><c>") & "</c></ch>"
End Function
Procedure check
As FilterXML returns findings of more than one element as a 2-dim array,
non-findings as Error 2015 and a single element as stand-alone value, it is necessary to distinguish between the returned var types:
Sub check(ByRef x, Optional ErrorResult As String = "")
'Purp: provide for correct xml result by checking var types
Select Case VarType(x)
Case vbError ' non-findings (Error 2015)
x = ErrorResult
Case Is >= vbArray ' 2-dim results (if more than 1 element)
x = Join(Application.Transpose(x), vbNullString)
'Case Else ' single element (here: digit, i.e. Double)
End Select
End Sub

How do I return a value from 2 overloaded functions with different return types?

I created two functions to import (make) an array from a text file. They have the same function names but different number of parameters. They also have return values which are different since one importArray function is returning a 1D array and the other is returning a 2D array.
Overloads Function importArray(fileName As String) As Array
Overloads Function importArray(fileName As String, splitter As Char) As Array
Sub Main()
Dim getArray As New MakeArray
Dim printArray() As String = getArray.importArray("array.txt")
For i = 0 To printArray.Length - 1
'printArray
Next
Console.ReadKey()
End Sub
I can't seem to wrap my head around this. I can enter 2 parameters when calling the function or 1 then it's fine, but I don't know how I could specify which function to call, because when I am printing the array I don't know whether to use the 1D or 2D array. I can't do 2 for loops since using one dimension or 2 throws an error "Expression is not a method" so I'm not sure how I can get around this.
Is there a way I could determine whether I am using a 1D or 2D array by reading the text file? I wanted to keep the code as efficient as possible.
Thank you!
Firstly, don't use the Array type that way. If the method return String array, that should be the return type. If it returns a 2D String array then that should be the return type.
Overloads Function ImportArray(fileName As String) As String()
Overloads Function ImportArray(fileName As String, splitter As Char) As String(,)
When you call one of the functions, you assign it to a variable of the appropriate type for the method you're calling. Just think of them as two different methods. Then, you either use a single loop of two nested loops to traverse the data.
Dim arr1 As String() = getArray.ImportArray(fileName)
For i = 0 To arr1.GetUpperBound(0)
'...
Next
Dim arr2 As String(,) = getArray.ImportArray(fileName, splitter)
For i = 0 To arr2.GetUpperBound(0)
For j = 0 To arr2.GetUpperBound(1)
'...
Next
Next

Split String into array and insert it into datagridview

I have a string of the form "1|2,3|4,56|7|8|9,10|93". This strin shall be split into an array at the "|". This array is then inserted into a 1-column datagridview.
I wrote this:
Private Function foo(input As String)
If input <> "" Then
Dim StringTable() As String = Split(input, "|")
Dim length As Integer = StringTable.Length
Debug.Print("length " & length)
For i = 0 To length - 1
Debug.Print(StringTable(i))
dg_ctdi.Rows.Add()
dg_ctdi.Rows(i).Cells(0).Value = StringTable(i)
Next
End If
End Function
Problem is, that "length" is now always 1, no matter how many elemenets the string has. Thus my datagridview has only one row. What am I missing?
Thanks!
Actually, the piece of code did the job correctly. Unfortunately I had some issues with the database-fild, where the input was previously stored. So feel free to use this code and have a look at the comments above. Thanks!

function to determine if a specific string of characters exists in an array

Given an array, I would like to have a function which determines if a string of characters exists in an array.
The string of characters must be EXACTLY the same in input of the function, and the array content.
Function IsInArray(ThsStrng As String, arr() As String, bnd As Integer) As Boolean
For Z = 1 To bnd
If arr(Z) = ThsStrng Then
IsInArray = True
Else
IsInArray = False
End If
Next Z
End Function
At first, it seemed like the function ran correctly. After using this function a few times, I noticed that the False value (meaning that the input string does not equal to a value in the array), was not correct (there were input values that were exactly the same a value in the array).
Please help,
Imagine what happens when the match is found in the middle of the array. The next iteration will be a mismatch, and the return value gets set back to False. You need to stop the loop when a match is found.
I believe the VBA syntax for that is
Exit For

Getting the index of item in an array VBA

I am trying to get the index of the item in an array VBA, but I have issue getting it.
Const NoOfVol As Integer = 5
Dim vol(NoOfVol) As Integer
For Index = 1 To NoOfVol
vol(Index) = Cells(15 + Index, 8).Value
Next
The array looks like this: (-2500,-1250,0,1250,2500). I am calling the function this way.
Function Find(ByVal Value As Variant, arr As Variant) As Integer
Find = Application.Match(Value, arr, False)
End Function
posOfVol = Find(-1250, vol)
But the posOfVol = 3, when it should be 2. Not sure where my error is. Need some guidance on this.
Your array is actually effectively declared as:
Dim vol(0 to NoOfVol) As Integer
unless you have an Option Base 1 statement. Since your loop goes from 1 to 5, you never populate the first element of the array and it retains its default value of 0. Therefore your array is actually:
(0,-2500,-1250,0,1250,2500)
and since you are looking for an exact match, -1250 is found at the third position.

Resources