0

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.

6
  • 1
    While I'm not convinced an array is necessary interim point merely to perform replaces or removal of characters, you can check out this this similar answer for converting a string into an array of its characters. Commented Jan 26, 2023 at 15:54
  • 3
    You need to size arr appropriately and your loop is wrong: For i = Len(strArg) To 1 step -1 Commented Jan 26, 2023 at 15:56
  • 2
    You could also assign the string to a byte array directly and process that. Commented Jan 26, 2023 at 16:02
  • 2
    Why not If IsNumeric(Mid$(strArg, i, 1)) Then nStr = nStr & Mid$(strArg, i, 1) (and going from 1 to Len(strArg) ofc) instead of using an array for it? Commented Jan 26, 2023 at 16:16
  • 1
    Posted an alternative using FilterXML as well as a function to atomize a string into a single character array based upon @JNevill 's comment. Commented Jan 26, 2023 at 21:02

3 Answers 3

2

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"
Sign up to request clarification or add additional context in comments.

Comments

1

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

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.