VBA Excel Formatting String with multiple periods - excel

I'm working with government harmonized codes. They're formatted as 10 numbers with periods between the 4th and 5th characters, and six-seventh characters like this "1234.56.7890". I'm trying to do some validation work so when a user enters a number without the periods, which is often the case, it puts the periods in for them.
The harmonized code is a variable in this instance named dimmed tv as a string.
Here's the code I'm using:
tv = Format(tv, "####.##.####")
Problem is, when I input 1234567890, it converts it instead to 1234567890.. with the two periods at the end. Any idea how I can get it to convert it to 1234.56.7890 as my code implies it should?

I'd do it like this:
Sub tester()
Dim e
For Each e In Array("1234.56.7899", "123456.7899", "1234.567899", _
"1234567899", "123A567899", "123456789")
Debug.Print e, ValidTv(e)
Next e
End Sub
'check format and return normalized value if possible
' return empty string if valid value can't be created
Function ValidTv(ByVal tv As String) As String
If tv Like "####.##.####" Then
ValidTv = tv
Else
tv = Replace(tv, ".", "")
If tv Like "##########" Then
ValidTv = Left(tv, 4) & "." & Mid(tv, 5, 2) & "." & Right(tv, 4)
End If
End If
End Function

Related

VBA - Parsing Date from Free Form Text String

I am attempting to parse out clean target DATES from cells populated with free form TEXT STRINGS.
ie: TEXT STRING: "ETA: 11/22 (Spring 4.5)" or "ETA 10/30/2019 EOD"
As you can see, there is no clear standard for the position of the date in the string, rendering LEFT or RIGHT formulas futile.
I tried leveraging a VBA function that I found which essentially breaks up the string into parts based on spaces in the string; however it has not been working.
Public Function GetDate(ResNotes As String) As Date
Dim TarDate As Variant
Dim part As Variant
TarDate = Split(ResNotes, " ")
For Each part In ResNotes
If IsDate(part) = True Then
GetDate = part
Exit Function
End If
Next
GetDate = "1/1/2001"
End Function
I'm referring to the cells with text strings as "ResNotes", short for "Resolution Notes" which is the title of the column
"TarDate" refers to the "Target Date" that I am trying to parse out
The result of the custom GETDATE function in Excel gives me a #NAME? error.
I expected the result to give me something along the lines of "10/30/2019"
Unless you need VBA for some other part of your project, this can also be done using worksheet formulas:
=AGGREGATE(15,6,DATEVALUE(MID(SUBSTITUTE(A1," ",REPT(" ",99)),seq_99,99)),1)
where seq_99 is a named formula and refers to:
=IF(ROW($A$1:INDEX($A:$A,255,1))=1,1,(ROW($A$1:INDEX($A:$A,255,1))-1)*99)
*seq_99 generates an array of numbers {1;99;198;297;396;495;...
Format the cell with the formula as a Date of some type.
If there are no dates, it will return an error which you can either leave, or wrap the function in an IFERROR(your_formula,your_error_message)
Algorithm
Split the cell on the spaces
Replace each space with 99 spaces
Using the MID function, return an array of substrings 99 characters long
Apply the DATEVALUE function which will return either an error (if the substring is not a date) or a date serial number.
Since dates in Excel are serial numbers since 1/1/1900, we can use the AGGREGATE function to pick out a value, and ignore errors.
If you are getting #NAME then the code is not stored in a general module. It should NOT be in a worksheet module or ThisWorkbook module.
Also there are few errors in the code. Split returns a String Array. And since IsDate returns TRUE/FALSE the = True is not needed.
As per #MathieuGuindon we can change the string to a date in the code if found and return an error if not. For that we need to allow the return to be a variant.
Public Function GetDate(ResNotes As String)
Dim TarDate() As String
Dim part As Variant
TarDate = Split(ResNotes, " ")
For Each part In TarDate
If IsDate(part) Then
GetDate = CDate(part)
Exit Function
End If
Next
GetDate = "1/1/2001"
'Instead of a hard coded date, one can return an error, just use the next line instead
'GetDate =CVErr(xlErrValue)
End Function
Approach isolating the date string via Filter function
Just for fun another approach demonstrating the use of the Filter function in combination with Split to isolate the date string and split it into date tokens in a second step; finally these tokens are transformed to date using DateSerial:
Function getDat(rng As Range, Optional ByVal tmp = " ") As Variant
If rng.Cells.count > 1 Then Set rng = rng.Cells(1, 1) ' allow only one cell ranges
If Len(rng.value) = 0 Then getDat = vbNullString: Exit Function ' escape empty cells
' [1] analyze cell value; omitted year tokens default to current year
' (valid date strings must include at least one slash, "11/" would be interpreted as Nov 1st)
tmp = Filter(Split(rng.Value2, " "), Match:="/", include:=True) ' isolate Date string
tmp = Split(Join(tmp, "") & "/" & Year(Now), "/") ' split Date tokens
' [2] return date
Const M% = 0, D% = 1, Y& = 2 ' order of date tokens
getDat = VBA.DateSerial(Val(tmp(Y)), Val(tmp(M)), _
IIf(tmp(D) = vbNullString, 1, Val(tmp(D))))
End Function

VBA VLookup Method not working for both numbers and strings

I have a workbook full of product codes and names. Contained within a form are various text boxes where a user can enter a code and its corresponding label will update with the name found in the workbook. Each text box runs the following sub when changed
Private Sub FindItem(x As Long)
Dim Name As Variant
Name = Application.VLookup(AddStockForm.Controls("Code" & x).Text, Sheet1.Range("B:C"), 2, False)
If IsError(Name) Then
AddStockForm.Controls("Name" & x).Caption = "Unknown Code"
Else
AddStockForm.Controls("Name" & x).Caption = Name
End If
End Sub
The sub takes the user input in the target box (e.g. Code1) and finds the corresponding name and writes it to the label (e.g. Name1). HOWEVER, the product codes are either strings, alphanumeric and plain text, OR numbers. For stupid reasons beyond my control, some codes have to be numbers, others have to contain letters.
This code works PERFECTLY for any code with a character in it (MYCODE or 500A) but not numbers, it writes "Unknown code" for any number, and they are in the lookup range. I have searched around stackoverflow and answers suggest declaring as variants, I've done this, even by assigning Controls().Text as a variant before using it in VLookup. I suspect the problem is
AddStockForm.Controls("Code" & x).Text
is a string. But I cannot convert to an INT because the user input might be a number or string.
Any ideas?
One thing you can do is to create a separate function which has the separate parts you want to do. In this instance, we are checking the input value first. If this is numerical we want to try doing the lookup as a string, then as a number if that fails. If the input value is not numerical we can go ahead and do the lookup as normal.
Public Function lookupStringOrInt(inputValue As Variant, tableArray As Range, colIndexNum As Long, Optional rangeLookup As Boolean) As Variant
If IsNumeric(inputValue) Then
lookupStringOrInt = Application.IfError(Application.VLookup(inputValue & "", tableArray, colIndexNum, rangeLookup), Application.VLookup(inputValue * 1, tableArray, colIndexNum, rangeLookup))
Else
lookupStringOrInt = Application.VLookup(inputValue, tableArray, colIndexNum, rangeLookup)
End If
End Function
You can then call this in your code with the line
name = lookupStringOrInt(AddStockForm.Controls("Code" & x) & "", Sheet1.Range("B:C"), 2, False)
If the value you are looking for does not exist, the function will return 'Error 2042'. You can choose to handle this however you like.

regex for Excel to remove all but specific symbols after a specific symbol?

I have stings like this which are addresses, e.g.:
P.O. Box 422, E-commerce park<br>Vredenberg<br><br><br>Curaçao
Adelgatan 21<br>Malmö<br><br>211 22<br>Sweden
Läntinen Pitkäkatu 35 A 15<br>Turku<br><br>20100<br>Finland
I am interested in Country only. Country always comes last after a <br> tag.
Note, that there can be several such tags preceding this last value (e.g. 1st example string).
Is there a good way to do a formula may ve along those lines:
Identify end of string
Loop a character back until one reaches ">" character
Cut everything else (including the ">" encountered)
You don't need RegEx to do this if it's always the last part of the string.
You can get it with String modifiers doing
Sub Test()
Dim str As String, str1 As String, str2 As String
Dim Countries As String
str = "P.O. Box 422, E-commerce park<br>Vredenberg<br><br><br>Curaçao"
str1 = "Adelgatan 21<br>Malmö<br><br>211 22<br>Sweden"
str2 = "La¨ntinen Pitka¨katu 35 A 15<br>Turku<br><br>20100<br>Finland"
Countries = Right(str, Len(str) - InStrRev(str, "<br>") - 3)
Countries = Countries + vbNewLine + Right(str1, Len(str1) - InStrRev(str1, "<br>") - 3)
Countries = Countries + vbNewLine + Right(str2, Len(str2) - InStrRev(str2, "<br>") - 3)
MsgBox Countries
End Sub
Obviously this will need to be updated for how your data set is stored. You can loop through the dataset and use the string modifier on each line
A formula works too. If a string in A1, write in B1:
=TRIM(RIGHT(SUBSTITUTE(A1,"<br>",REPT(" ",100)),100))
Modified using an approach taken from here:
https://exceljet.net/formula/get-last-word

How can I pick specific string fragments out of an excel cell using a custom formula written in VBA

At work I am required to reformat incorrect Addresses on a weekly basis from records in our Salesforce instance. We gather the incorrectly formatted addresses using a Report and export them to an Excel file. My job is simply to manipulate the data in the file to format them properly then reinsert them into the database.
Typically the addresses are formatted as so:
5 Sesame Street, Anytown, Anyplace
Separating these can be done easily by hand, but I typically have to work with hundreds of addresses at a time, and using default excel formulas tends to require lots of wrangling multiple cells at once to break it up into fragments.
Thus I wrote a custom formula to run through the cell and return a specific fragment of the string based on the "Comma Number" given. So if I give a Comma Number of 1, I would get "5 Sesame Street", 2 would get me "Anytown", etc.
Here is my code so far:
Public Function fragmentAddress(address As String, numberofcommas As Integer) As String
seen = 1
lastComma = -1
Dim x As Long
Dim frag As Long
For x = 0 To Len(address)
If Mid(address, x, 1) = "," & numberofcommas = seen Then
Exit For
ElseIf Mid(address, x, 1) = "," & numberofcommas <> seen Then
seen = seen + 1
lastComma = x
End If
Next
frag = Mid(address, lastComma + 1, seen - lastComma)
fragmentAddress = frag
I have not implemented the ability to handle the final value yet, but it does not give me any outputs, only outputting a "#VALUE!" error when I attempt to give it the input
=fragmentAddress("3 Ashley Close, Charlton Kings",1)
I have some experience with programming, but this is my first time writing anything in VBA.
Any help would be appreciated, thank you.
Not exactly sure what your question is, but this is simpler:
Public Function GetAddressFragment(ByVal Address As String, ByVal Index As Integer) As String
Dim addr() As String
addr = Split(Address, ",")
On Error Resume Next
GetAddressFragment = Trim(addr(Index - 1))
End Function

Excel VBA Inventory sorting

I'm trying to make the inventory scan process a bit simple.
We scan the incoming shipment. The scanner sends a string to Excel something like 'XYZ123'.
What I'm trying to do is, instead of the user selecting the column manually, I'd like excel to send the scanned string to the respective column.
For example, let us say there are 3 possible columns 'PO', 'Item', 'SN'
PO will start with 'XYZ'
Item will start with 'ABC'
SN with start with 'LMN'
If the scanned value starts with 'ABC', it has to be sent to the 'Item' column.
Is this possible? I tried playing with the Search, Exact and few other formulas, nothing worked so far.
Thank you,
Sub test_inventory_sorting()
Dim v_arr(1 To 3) As String, v As Variant
v_arr(1) = "XYZ1234"
v_arr(2) = "LMN73456"
v_arr(3) = "ABCzxcv"
For Each v In v_arr
Debug.Print v; " goes to "; get_col(CStr(v))
Next v
End Sub
Function get_col(ByVal p_val As String) As String
If p_val Like "ABC*" Then
get_col = "SN"
ElseIf p_val Like "LMN*" Then
get_col = "Item"
ElseIf p_val Like "XYZ*" Then
get_col = "PO"
Else
get_col = "Invalid"
End If
End Function

Resources