Proper use of boolean/case? - vba

I'm having issues figuring out if I properly wrote this function. It'll be fed a string that either contains a "%" or a "#" as the last character ie. "TA_PQ_SI02_%". I just want this function to tell me if it's a % or #.
Did I do this in the most effiecient/proper way? I think not, and would like to learn why.
Private Function numberOrPercentCheck(ByVal cleanCode As String) As Boolean
Select Case cleanCode
Case Right(cleanCode , 1) = "#"
numberOrPercentCheck= True
Case Right(cleanCode , 1) = "%"
numberOrPercentCheck= False
Case Else
Debug.Print "Error: " & cleanCode & " is not formatted properly with a # or % at the end, and has been set to a default #"
numberOrPercentCheck = True
End Select
End Function

When you just want a Boolean:
Private Function numberOrPercentCheck(ByVal cleanCode As String) As Boolean
numberOrPercentCheck = Right(cleanCode, 1) = "#"
End Function
When you need a third possibility:
Private Function numberOrPercentCheck(ByVal cleanCode As String) As Variant
Select Case Right(cleanCode, 1)
Case "#": numberOrPercentCheck = True
Case "%": numberOrPercentCheck = False
Case Else: numberOrPercentCheck = "Error: " & cleanCode & " is not formatted properly with a # or % at the end"
End Select
End Function

Related

Vba to find if a string split is null?

I have an access database, in many of the tables is a field called "Notes".
This field is used by techs to, well, make notes on the equipment.
But these notes need to be broken up into useful groups, as such we've chosen to use "|" as the delimiter. ( . , ; : - _ / \ all have valid notes uses and can not be assigned to this role)
I've tried :
If Split(rst!Notes, "|")(1).Property = "" Then
aNotesOver = ""
Else
aNotesOver = Split(rst!Notes, "|")(1)
End If
'AND:
If Split(rst!Notes, "|")(1) <> "" Then
aNotesOver = Split(rst!Notes, "|")(1)
Else
aNotesOver = Nz(Split(rst!Notes, "|"), "")
End If
'AND:
If Nz(Split(rst!Notes, "|")(1)) = "" Then
aNotesOver = ""
Else
aNotesOver = Split(rst!Notes, "|")(1)
End If
'AND I tried:
If Not IsNull(Split(rst!Notes, "|")(1)) Then
aNotesOver = Split(rst!Notes, "|")(1)
Else
aNotesOver = ""
End If
None of them work, and I keep getting the "Invalid use of Null " Error.
Anyone have any suggestions?
This is one of those unfortunate quirks of VBA. if the passed value is null, then the split function fails.
and if you pass a empty string, then the ubound() value of the array is -1!!!!
So, this is messy.
I would suggest that you build your own custom function:
Public Function MySplit(v As Variant, ix As Integer) As String
MySplit = ""
If IsNull(v) Then Exit Function
If v = "" Then Exit Function
Dim vBuf As Variant
vBuf = Split(v, "|")
If ix > UBound(vBuf) Then Exit Function
MySplit = vBuf(ix)
End Function
So you could add a delimter to this function.
But, now your code is:
aNotesOver = MySplit(rst!Notes, 1)
And if the 1 is larger then the number of values, it will still return ""

How to code an sql string in vba to use greater than or less than symbols in my MS Access form, when searching for dates in one textbox

I have a list of records that I can search by inputting various date or selecting between dates, and using sql script it returns the results. But I would like to know how can I use greater than symbol in the date textbox and have sql script recognize it and return dates greater than for example ">7/1/2021"
Thank you for your help.
The way that I would do this is to use a combo box that has the various operators (<=,<,=,>,>=) stored as a value list, in addition to the text box that has the date. This is a good idea as you limit the choices that the user can make for the comparison, and you still get to use the input mask for the date field in the combo box.
You can then concatenate the comparison and the date to a SQL string that provides the search. Something like:
Private Sub cmdSearch_Click()
On Error GoTo E_Handle
Dim strSQL As String
Const JetDateFmt = "\#mm\/dd\/yyyy\#;;;\N\u\l\l"
strSQL = "SELECT * " _
& " FROM TB_Edditions " _
& " WHERE ED_Start_Date " & Me!cboOperator & Format(Me!txtDate, JetDateFmt) _
& " ORDER BY ID ASC;"
Me!lstResult.RowSource = strSQL
sExit:
On Error Resume Next
Exit Sub
E_Handle:
MsgBox Err.Description & vbCrLf & vbCrLf & "frmDateSearch!cmdSearch_Click", vbOKOnly + vbCritical, "Error: " & Err.Number
Resume sExit
End Sub
In this instance I am using the SQL created to populate a list box. You will note that I am forcing the date entered to be in a specific format, so that it is interpreted correctly.
It is unclear how you are invoking the sql query and that matters, but one approach is you can access public functions anywhere in access. So if you have public functions GetOperator and GetDate you can either pass them as parameters to the sql query, bind them to the sql query directly, or use them in the designer:
For a case like < or > and a date you want to validate the textbox entry first. I tried to validate using the textbox validation rule but apparently this case was too complicated. I ended up having to use the textbox BeforeUpdate Event.
Private Sub txtFilter_BeforeUpdate(Cancel As Integer)
'text box name is txtFilter
If isValidOperator(Me.txtFilter) And isValidDate(Me.txtFilter) Then
Cancel = False
setmysearchcriteria = Me.txtFilter
Else
MsgBox "Search criteria must be in the form of operatordate such as <4/12/21", vbOKOnly
Cancel = True
Exit Sub
End If
End Sub
Public Function isValidOperator(strText As String) As Boolean
Dim operator As String
operator = Left(strText, 1)
If operator = ">" Or operator = "<" Then
SetOperator (operator)
isValidOperator = True
Else
isValidOperator = False
End If
End Function
Private Function isValidDate(strDate As String) As Boolean
strDate = Mid(strDate, 2)
If IsDate(strDate) Then
SetDate (strDate)
isValidDate = True
Else
isValidDate = False
End If
End Function
Here is the code for the public functions serving as synthetic properties. Just pass the Get functions as parameters or invoke them as functions directly in the sql.
Private strMyDate As String
Private myoperator As String
Public Function SetDate(strDate As String) As Boolean
strMyDate = "#" & strDate & "#"
SetDate = True
End Function
Public Function GetDate() As String
GetDate = strMyDate
End Function
Public Function SetOperator(operator As String) As Boolean
myoperator = operator
SetOperator = True
End Function
Public Function GetOperator() As String
GetOperator = myoperator
End Function
In most case you will want to trigger your sql in the textbox AfterUpdate event. For instance Changes to the form your textbox is in will not show if you trigger your sql in the BeforeUpdate event.
Private Sub txtFilter_AfterUpdate()
'trigger your sql here instead of setting the filter
Me.Filter = "ADate " & GetOperator & " " & GetDate
Debug.Print Me.Filter
Me.FilterOn = True
Me.Requery
End Sub
Like #braX said, enclose your date literals inside two # characters..

Recursive function returning empty string

How do I properly exit a recursive function and return a value in VBA?
I have this simple code to remove multiple spaces from a string:
Public Function RemoveMultipleSpaces(s As String) As String
If InStr(1, s, " ", vbTextCompare) > 0 Then
Dim newS As String
newS = Replace(s, " ", " ")
RemoveMultipleSpaces (newS)
Else
RemoveMultipleSpaces = s
End
End If
End Function
But depending on what I use to exit either End or Exit Function, I either get nothing returned or an empty string.
A proper recursive function doesn't need a specific exit condition. You just stop calling the function recursively, and it exits.
However, if you want to explicitly exit, you can use Exit Function.
Your mistake, however, is that when you make a recursive call, you need to return the result of the recursive call.
Public Function RemoveMultipleSpaces(s As String) As String
If InStr(1, s, " ", vbTextCompare) > 0 Then
Dim newS As String
newS = Replace(s, " ", " ")
RemoveMultipleSpaces = RemoveMultipleSpaces(newS)
Else
RemoveMultipleSpaces = s
End If
End Function

VBA Handling multiple custom datatype possibilities

I have done some research and haven't found any similar question.
I have a VBA macro that imports a .CSV file containing telegrams sent by a device.
In the end of this macro, I want to create a graph with the time elapsed on the x-axis and the value corresponding to the telegram.
The issue is that this value can be of different types: hexadecimal, boolean, integer... And that they don't respect the standard Excel number format, which means that they can't be used to create a graph.
Here are some examples (with " around the value to show its start and end) :
hexadecimal : "A7 C8"
Boolean : "$00" or ""$01"
Percentage : "$30"
And here is an example of data, with custom time format and boolean value
Here is my related code so far, where I try to convert into a custom type then convert back to numeric to get a common number datatype :
If wsRes.Range("R1").Value Like "$##" Then
wsRes.Range("R1:R" & plotLine).NumberFormat = "$##"
wsRes.Range("R1:R" & plotLine).NumberFormat = General
End If
If wsRes.Range("R1").Value Like "??[ ]??" Then
Dim valArray(1) As String
For i = 1 To plotLine Step 1
valArray = Split(wsRes.Range("R" & i), " ")
wsRes.Range("R" & i).Value = ToInt32(valArray(0) + valArray(1), 16)
wsRes.Range("" & i).NumberFormat = General
Next i
End If
I haven't been able to test it with hexa yet, but the conversion trick doesn't work with percentage/boolean
EDIT :
First, thank you for your answers.
Here is my final code for anyone's interested, adapted from Vityata's.
This method will allow to easily add other datatypes if needed.
Sub TestMe()
Dim RangeData as String
Set wsRes = ActiveWorkbook.Sheets("Results")
For i = 1 To plotLine Step 1 'plotLine is the last line on which I have data
DetectType wsRes.Range("R" & i).Value, i
Next i
RangeData = "Q1:R" & plotLine
CreateGraph RangeData 'Call My sub creating the graph
End Sub
Public Sub DetectType(str As String, i As Integer)
Select Case True
Case wsRes.Range("R" & i).Value Like "??[ ]??"
wsRes.Range("R" & i).Value = HexValue(str)
Case wsRes.Range("R" & i).Value Like "?##"
wsRes.Range("R" & i).Value = DecValue(str)
Case Else
MsgBox "Unsupported datatype detected : " & str
End
End Select
End Sub
Public Function HexValue(str As String) As Long
Dim valArray(1) As String 'Needed as I have a space in the middle that prevents direct conversion
valArray(0) = Split(str, " ")(0)
valArray(1) = Split(str, " ")(1)
HexValue = CLng("&H" & valArray(0) + valArray(1))
End Function
Public Function DecValue(str As String) As Long
DecValue = Right(str, 2)
End Function
You need three boolean functions, following your business logic and some of the Clean Code principles (although the author of the book does not recognize VBA people as programmers):
IsHex()
IsBoolean()
IsPercentage()
Public Sub TestMe()
Dim myInput As Variant
myInput = Array("A7C8", "$01", "$30")
Dim i As Long
For i = LBound(myInput) To UBound(myInput)
Debug.Print IsHex(myInput(i))
Debug.Print IsBoolean(myInput(i))
Debug.Print IsPercentage(myInput(i))
Debug.Print "-------------"
Next i
'or use this with the DetectType() function below:
'For i = LBound(myInput) To UBound(myInput)
' Debug.Print DetectType(myInput(i))
'Next i
End Sub
Public Function IsHex(ByVal str As String) As Boolean
On Error GoTo IsHex_Error
IsHex = (WorksheetFunction.Hex2Dec(str) <> vbNullString)
On Error GoTo 0
Exit Function
IsHex_Error:
End Function
Public Function IsBoolean(ByVal str As String) As Boolean
IsBoolean = CBool((str = "$00") Or (str = "$01"))
End Function
Public Function IsPercentage(ByVal str As String) As Boolean
IsPercentage = (Len(str) = 3 And Left(str, 1) = "$" And IsNumeric(Right(str, 2)))
End Function
Then some additional logic is needed, because $01 is both Boolean and Percentage. In this case, you can consider it Percentage. This is some kind of a mapper, following this business logic:
Public Function DetectType(str) As String
Select Case True
Case IsHex(str)
DetectType = "HEX!"
Case IsPercentage(str) And IsBoolean(str)
DetectType = "Boolean!"
Case IsPercentage(str)
DetectType = "Percentage!"
Case Else
DetectType = "ELSE!"
End Select
End Function

Cut Special String - VBA

my Question is how to check if a string have a "text" & "_" at beginning.
For Example:
If sText = test.docx Then Function = False
ElseIF sText = Test_test.docx Then Function = True
End If
how i cut this string correctly, also when the text before the _ is not test and if there are several _ in the string it also works
use Instr() as shown here:
foo="test"&"_"
bar="test_test.docx"
if Instr(bar, foo)>0 then function = true
else function = false
end if
Instr(bar,foo) shows position of substring foo in string bar.
If there s no such substring, then it returns zero
If you need to check any text, that is not a problem, use this condition:
foo="_"
n=4
bar"test_textt.docx"
m=Instr(bar,foo)
if (m>n)and(len(bar)>m) then function=true
else function=false
end if
here n - number of characters, that would be before ""
If you dont know how many characters there may be, just set n to 0 or 1
if "" migth be last character, then delete condition (len(bar)>m)
You can simply check if the string begin with test_
dim res as boolean, filename as string
res = false
filename = ""
' if the len is not Superior to 5 (len of test_), don't check
if len(sText) > 5 then
' if the left part begin with test_
if left(lcase(sText), 5) = "test_" then
res = true
' if you want to retrieve the filename without test
filename = mid(sText, 6)
end if
end if