VBA swap words in a string - excel

In VBA I've made an userform. It contains multiple text boxes in which the user can write text. In one text box the user is supposed to type in his last name. I've made a variable called lastname and then did lastname = LastnameBox.Value.
My question is:
If someone for example types de Vries, how can I change this in Vries, de. Or if someone types van de Voort van Zijp, I need to change this in Voort van Zijp, van de.
How could I make this possible in VBA?

I would try something along these lines. Not sure how you are requiring separation, I used "de" as this
Function NamesTest(strNameIn As String)
Dim a() As String
a = Split(strNameIn, "de")
a(0) = a(0) & " de"
NamesTest = a(1) & "," & a(0)
End Function

Here are two options. The first will pick up the last word and do the swap. It pays no attention to letter case.
Sub LastFirst()
Debug.Print RevLast("de Vries")
Debug.Print RevLast("van der Straat")
Debug.Print RevLast("van de drake")
End Sub
Function RevLast(Name)
LastName = Trim(Right(Replace(Name, " ", String(99, " ")), 99))
LenLastName = Len(LastName)
FirstPart = Left(Name, Len(Name) - (LenLastName + 1))
RevLast = LastName + ", " + FirstPart
End Function
The second only swaps of there is an uppercase letter.
Sub UppercaseFirst()
Name = "de Vries"
Name = "van der Straat"
Debug.Print RevUpper("de Vries")
Debug.Print RevUpper("van der Straat")
Debug.Print RevUpper("van de drake")
End Sub
Function RevUpper(Name)
FirstUpper = -1
On Error Resume Next
xStr = Trim(Rg.Value)
For j = Len(Name) To 1 Step -1
If (Asc(Mid(Name, j, 1)) < 91) And (Asc(Mid(Name, j, 1)) > 64) Then
FirstUpper = Len(Name) - j + 1
Exit For
End If
Next
If FirstUpper > 0 Then
LastName = Right(Name, FirstUpper)
FirstPart = Left(Name, Len(Name) - (FirstUpper + 1))
NewName = LastName + ", " + FirstPart
RevUpper = NewName
Else
RevUpper = "Invalid"
End If
End Function
Function RevNm(Name)
FirstUpper = -1
On Error Resume Next
xStr = Trim(Rg.Value)
For j = Len(Name) To 1 Step -1
If (Asc(Mid(Name, j, 1)) < 91) And (Asc(Mid(Name, j, 1)) > 64) Then
FirstUpper = Len(Name) - j + 1
Exit For
End If
Next
If FirstUpper > 0 Then
LastName = Right(Name, FirstUpper)
FirstPart = Left(Name, Len(Name) - (FirstUpper + 1))
NewName = LastName + ", " + FirstPart
RevNm = NewName
Else
RevNm = "Invalid"
End If
End Function

Here's a more general-purpose solution for the problem stated in the title (won't handle the specifics of inverting first name / last name, which is a different problem):
Public Function ReverseWords(ByVal value As String) As String
Dim words As Variant
words = VBA.Strings.Split(value, " ")
Dim result As String, i As Long
For i = LBound(words) To UBound(words)
result = words(i) & " " & result
Next
ReverseWords = result
End Function
Usage:
Debug.Print ReverseWords("the quick brown fox jumps over the lazy dog")
Outputs:
dog lazy the over jumps fox brown quick the
To the OP though, this isn't about inverting the words in a string at all. The solution is to parse the given string.
The first capital letter is indeed where I want to swap
So you need to find the index of the first capital letter in the input string, then extract the first & last name, trim them, then concatenate them.
This works:
Public Function ReverseFullName(ByVal value As String) As String
Dim firstCapitalIndex As Long, i As Long
For i = 1 To Len(value)
If IsCapitalLetter(Mid$(value, i, 1)) Then
firstCapitalIndex = i
Exit For
End If
Next
If i = 1 Then
'already shaped as needed
ReverseFullName = value
Exit Function
End If
Dim firstName As String
firstName = Trim$(Left$(value, firstCapitalIndex - 1))
Dim lastName As String
lastName = Trim$(Mid$(value, firstCapitalIndex))
ReverseFullName = lastName & ", " & firstName
End Function
Private Function IsCapitalLetter(ByVal value As String) As Boolean
Dim asciiCode As Integer
asciiCode = Asc(value)
IsCapitalLetter = asciiCode >= Asc("A") And asciiCode <= Asc("Z")
End Function
Usage:
Debug.Print ReverseFullName("van de Voort van Zijp")
Debug.Print ReverseFullName("de Vries")
Debug.Print ReverseFullName("Voort van Zijp, van de")
Outputs:
Voort van Zijp, van de
Vries, de
Voort van Zijp, van de

Related

Converting a string with date in US format to UK format

I am trying to convert a string, which has a date in US format into UK format.
The following code seems to be hit or miss when it comes to a date that is single digits for both the day and the month:
X = 3
Do While strTimeStamp = 0
If InStr(WS2.Cells(lRow, lCol), "TIMESTAMP") <> 0 Then
strHPCStats = Split(WS2.Cells(lRow, lCol), " ")
'strHPCStats(X) = Mid(strHPCStats(X), 4, 6)
re.Pattern = "^(\d{2})(\d{2})(\d{4})$"
strHPCStats(X) = re.Replace(strHPCStats(X), "$3/$2/$1")
strHPCStats(X) = Format$(strHPCStats(X), "dd/mmm/yyyy")
strTimeStamp = strHPCStats(X)
WS2.Cells(lRow, lCol).EntireRow.Delete
lRow = lRow - 1
Else
WS2.Cells(lRow, lCol).EntireRow.Delete
lRow = lRow - 1
End If
lRow = lRow + 1
Loop
The typical string:
4:19:17 (application) TIMESTAMP 3/13/2022
The string where it is having trouble:
5:36:32 (cameo) TIMESTAMP 4/1/2022
d{2} will look for exactly 2 digits, so if your date has a month (or day) with only 1 digit, the regex doesn't match.
If you want to specify 1 or 2 digits, you can for example use d{1,2}, so the statement would be
e.Pattern = "^(\d{1,2})(\d{1,2})(\d{4})$"
Details: How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops
There's no need to use regular expressions, given your expected data.
Just look for two slashes in a space-separated string:
Function us2ukDate(S As String) As Date
Dim v, w, x
v = Split(S, " ")
For Each w In v
If (Len(w) - Len(Replace(w, "/", ""))) = 2 Then
x = Split(w, "/")
us2ukDate = DateSerial(x(2), x(0), x(1))
Exit Function
End If
Next w
End Function
testing example
If, instead of just returning the date, you want to change the format within the string, you could do something like:
Sub convertStrings()
Const d1 = "4:19:17 (application) TIMESTAMP 3/13/2022"
Const d2 = "5:36:32 (cameo) TIMESTAMP 4/1/2022"
Dim sParts
sParts = Split(d1, " ")
sParts(UBound(sParts)) = Format(us2ukDate(sParts(UBound(sParts))), "dd-mmm-yyyy")
Debug.Print Join(sParts, " ")
sParts = Split(d2, " ")
sParts(UBound(sParts)) = Format(us2ukDate(sParts(UBound(sParts))), "dd-mmm-yyyy")
Debug.Print Join(sParts, " ")
End Sub

I am having trouble understanding certain parts of this code. What is break_space_position and what are the bounds of this For Next loop?

I am trying to understand this code. In following the logic, I am not understanding the bounds of the For Next loop (what is next referring to? where does it end?) and what break_space_position is. Hoping you all can help.
I've already tried reading about For Next loops and googling break_space_position
Sub parse_names()
Dim thename As String
Dim spaces As Integer
Do Until ActiveCell = ""
thename = ActiveCell.Value
spaces = 0
For test = 1 To Len(thename)
If Mid(thename, test, 1) = " " Then
spaces = spaces + 1
End If
Next
If spaces >= 3 Then
break_space_position = space_position(" ", thename, spaces - 1)
Else
break_space_position = space_position(" ", thename, spaces)
End If
If spaces > 0 Then
ActiveCell.Offset(0, 1) = Left(thename, break_space_position - 1)
ActiveCell.Offset(0, 2) = Mid(thename, break_space_position + 1)
Else
' this is for when the full name is just a single name with no spaces
ActiveCell.Offset(0, 1) = thename
End If
ActiveCell.Offset(1, 0).Activate
Loop
End Sub
Function space_position(what_to_look_for As String, what_to_look_in As String, space_count As Integer) As Integer
Dim loop_counter As Integer
space_position = 0
For loop_counter = 1 To space_count
space_position = InStr(loop_counter + space_position, what_to_look_in, what_to_look_for)
If space_position = 0 Then Exit For
Next
End Function
if the original cell contains "Dr. William Healer" then after running this code there would be a cell containing "Dr. William" and a cell containing "Healer." My ultimate goal once I understand this block of code is to edit it to make the result "William" "Healer"
You can insert other tokens in addition to Dr. or Mrs.. Just divide them by | pipe character.
Function GetFirstName$(cell$)
With CreateObject("VBScript.RegExp")
.Pattern = "(Dr.|Mrs.)*\s*(\w+)"
With .Execute(cell)
If .Count > 0 Then
GetFirstName = .Item(0).SubMatches(1)
End If
End With
End With
End Function
Sub TestGFN()
MsgBox GetFirstName("Dr. William Healer") '// => WIlliam
MsgBox GetFirstName("Bob Smith MBA") '// => Bob
End Sub
I realy liked #JohnyL approach with regular expression, so I wanted to expand on this a bit:
Option Explicit
Public Type FullName
First As String
Last As String
End Type
Public Enum NameToChoose
FirstName = 0
LastName = 1
End Enum
Public Function GetName(Value As String, ChosenName As NameToChoose) As String
Dim fn As FullName
With CreateObject("VBScript.RegExp")
.Pattern = "^((Dr.|OtherPrefix)\s)?(\w+)\s(\w+)(\s(MBA|OtherPostFix))?$"
With .Execute(Value)
If .Count > 0 Then
fn.First = .Item(0).SubMatches(2)
fn.Last = .Item(0).SubMatches(3)
End If
End With
End With
Select Case ChosenName
Case NameToChoose.FirstName
GetName = fn.First
Case NameToChoose.LastName
GetName = fn.Last
End Select
End Function
Sub TestFunction()
Debug.Print GetName("Dr. William Healer", FirstName) ' "William"
Debug.Print GetName("Dr. William Healer", LastName) ' "Healer"
Debug.Print GetName("Bob Smith MBA", FirstName) ' "Bob"
Debug.Print GetName("Bob Smith MBA", LastName) ' "Smith"
End Sub

Extend vlookup to calculate cost of goods

I have sales report from e-shop and need to calculate cost of goods for each order line. Order line can look like one of these:
2x Lavazza Crema e Aroma 1kg - 1x Lavazza Dolce Caffe Crema 1kg
1x Lavazza Vending Aroma Top 1kg - 1x Arcaffe Roma 1Kg - 1x Kimbo - 100% Arabica Top Flavour
So, what I need Excel to do is to take each product, find its cost with vlookup function from another sheet and then multiply it with amount ordered. The issue is that nr of products ordered can vary from 1 to 10+.
I tried to calculate it with VBA, but the code is not working (I didn´t use multiplying at the moment, I know)
Maybe it is possible to solve this problem with excel formulas?
Function GoodsCost(str, Optional strDelim As String = " ")
larray = Split(str, strDelim)
Set lookup_range = Worksheets("Products").Range("B:E")
For i = LBound(larray) To UBound(larray)
skuarray = Split(larray(i), "x ")
skucost = Application.WorksheetFunction.VLookup(UBound(skuarray), lookup_range, 4, False)
cost = cost + skucost
Next i
GoodsCost = cost
End Function
Well, it seems like now the problem is solved. Of course, it works only if make an assumption that dashes(-) are not present in product descriptions. But it can be set up in product list. The other opportunity is to use another delimeter (for example "/"). We can use Ctrl+F to find all combinations like "x -" and replace them with "x /")
Function GoodsCost(str)
Dim answer As Double
Set Products = Worksheets("Products").Range("B:E")
larray = Split(str, " - ")
For i = LBound(larray) To UBound(larray)
sku = Split(larray(i), "x ")
Price = Application.WorksheetFunction.VLookup(sku(1), Products, 4, False) * sku(0)
answer = answer + Price
Next i
GoodsCost = answer
End Function
Below you find a UDF (User Defined Function) which you can use in your worksheet. After installing it in a standard code module (VBE names these like "Module1") you can call it from the worksheet like =CostOfGoods($A2) where A2 is the cell containing and order line as you have described.
Option Explicit
Function CostOfGoods(Cell As Range) As Single
' 15 Jan 2018
Const Delim As String = " - "
Dim Fun As Single ' function return value
Dim Sale As Variant
Dim Sp() As String
Dim i As Long
Dim PriceList As Range
Dim Qty As Single, Price As Single
Dim n As Integer
Sale = Trim(Cell.Value)
If Len(Sale) Then
Sp = Split(Sale, Delim)
Do While i <= UBound(Sp)
If InStr(Sp(i), "x ") = 0 Then
If Not ConcatSale(Sp, i, Delim) Then Exit Do
End If
i = i + 1
Loop
With Worksheets("Products")
i = .Cells(.Rows.Count, "B").End(xlUp).Row
' price list starts in row 2 (change as required)
Set PriceList = Range(.Cells(2, "B"), .Cells(i, "E"))
End With
For i = 0 To UBound(Sp)
Qty = Val(Sp(i))
n = InStr(Sp(i), " ")
Sp(i) = Trim(Mid(Sp(i), n))
On Error Resume Next
Price = Application.VLookup(Sp(i), PriceList, 4, False)
If Err Then
MsgBox "I couldn't find the price for" & vbCr & _
Sp(i) & "." & vbCr & _
"The total cost calculated excludes this item.", _
vbInformation, "Price not found"
Price = 0
End If
Fun = Fun + (Qty * Price)
Next i
End If
CostOfGoods = Fun
End Function
Private Function ConcatSale(Sale() As String, _
i As Long, _
Delim As String) As Boolean
' 15 Jan 2018
Dim Fun As Boolean ' function return value
Dim x As Long, f As Long
x = UBound(Sale)
If (i > 0) And (i <= x) Then
i = i - 1
Sale(i) = Sale(i) & Delim & Sale(i + 1)
For f = i + 1 To x - 1
Sale(f) = Sale(f + 1)
Next f
Fun = True
End If
If Fun Then ReDim Preserve Sale(x - 1)
ConcatSale = Fun
End Function
I have tested this and it works with dashes in product description:
Function GoodsCost(str, Optional strDelim As String = " ")
larray = Split(str, " ")
'split the cell contents by space
Set lookup_range = Worksheets("Products").Range("B:E")
'set lookup range
For i = LBound(larray) To UBound(larray) 'loop through array
nextproduct:
LPosition = InStr(larray(i), "x") 'find multiplier "x" in string
If LPosition = Len(larray(i)) Then 'if the last character is x
If Product <> "" Then GoTo lookitup 'lookup product
Quantity = larray(i) 'get quantity
Else
Product = Product & " " & larray(i) 'concatenate array until we get a full product description to lookup with
End If
Next i
lookitup:
If Right(Product, 2) = " -" Then Product = Left(Product, Len(Product) - 2)
If Left(Product, 1) = " " Then Product = Right(Product, Len(Product) - 1)
'above trim the Product description to remove unwanted spaces or dashes
cost = Application.WorksheetFunction.VLookup(Product, lookup_range, 4, False)
Quantity = Replace(Quantity, "x", "")
GoodsCost = cost * Quantity
MsgBox Product & " # Cost: " & GoodsCost
Product = ""
If i < UBound(larray) Then GoTo nextproduct
End Function
I'd use Regular Expressions to solve this. First it finds in the string were the 'delimiters' are by replacing the - with ; detecting only - that are next to a number followed by an x (i.e. a multiplier so ignoring - in product names). It then splits each of these results into a quantity and the product (again using RegEx). It then finds the product in your data and returns the cost of goods. If there is an error, or the product isn't in your data it returns a #Value error to show that there is an issue.
Public Function GoodsCost(str As String) As Double
Dim lookup_range As Range, ProductMatch As Range
Dim v, Match
Dim qty As Long
Dim prod As String
Dim tmp() As String
On Error GoTo err
Set lookup_range = Worksheets("Products").Range("B:E")
With CreateObject("vbscript.regexp")
.Global = True
.ignorecase = True
.pattern = "(\s\-\s)(?=[0-9]+x)"
If .test(str) Then
tmp = Split(.Replace(str, ";"), ";")
Else
ReDim tmp(0)
tmp(0) = str
End If
.pattern = "(?:([0-9]+)x\s(.+))"
For Each v In tmp
If .test(v) Then
Set Match = .Execute(v)
qty = Match.Item(0).submatches.Item(0)
prod = Trim(Match.Item(0).submatches.Item(1))
Set ProductMatch = lookup_range.Columns(1).Find(prod)
If Not ProductMatch Is Nothing Then
GoodsCost = GoodsCost + (qty * ProductMatch.Offset(0, 3))
Else
GoodsCost = CVErr(xlErrValue)
End If
End If
Next v
End With
Exit Function
err:
GoodsCost = CVErr(xlErrValue)
End Function

How can I find quoted text in a string?

Example
Say I have a string:
"I say ""Hello world"" and she says ""Excuse me?"""
VBA will interpret this string as:
I say "Hello world" and she says "Excuse me?"
A more complex example:
I have a string:
"I say ""Did you know that she said """"Hi there!"""""""
VBA interprets this string as:
I say "Did you know that she said ""Hi there!"""
If we remove "I say "
"Did you know that she said ""Hi there!"""
we can continue parsing the string in vba:
Did you know that she said "Hi there!"
Problem
Ultimately I want some function, sBasicQuote(quotedStringHierarchy as string), which returns a string containing the next level up in the string hierarchy.
E.G.
dim s as string
s = "I say ""Did you know that she said """"Hi there!"""""""
s = sBasicQuote(s) ' returns 'I say "Did you know that she said ""Hi there!"""'
s = sBasicQuote(s) ' returns 'Did you know that she said "Hi there!"'
s = sBasicQuote(s) ' returns 'Hi there!'
I just can't figure out an algorithm that would work with this... You almost need to replace all double quotes, but when you've replaced the nth double quote you have to skip to the n+1th douple quote?
How does one implement this in VBA?
You could do something like this
Public Sub test()
Dim s As String
s = "I say ""Did you know that she said """"Hi there!"""""""
Debug.Print DoubleQuote(s, 0)
Debug.Print DoubleQuote(s, 1)
Debug.Print DoubleQuote(s, 2)
End Sub
Public Function DoubleQuote(strInput As String, intElement As Integer) As String
Dim a() As String
strInput = Replace(strInput, String(2, Chr(34)), String(1, Chr(34)))
a = Split(strInput, chr(34))
DoubleQuote = a(intElement)
End Function
Another slightly modified version is a little more accurate
`Public Function DoubleQuote(strInput As String, intElement As Integer) As String
Dim a() As String
Dim b() As String
Dim i As Integer
ReDim b(0)
a = Split(strInput, Chr(34))
' ***** See comments re using -1 *******
For i = 0 To UBound(a) - 1
If Len(a(i)) = 0 Then
b(UBound(b)) = Chr(34) & a(i + 1) & Chr(34)
i = i + 1
Else
b(UBound(b)) = a(i)
End If
ReDim Preserve b(UBound(b) + 1)
Next i
DoubleQuote = b(intElement)
End Function`
I think the following will return what you are looking for in your nested quote example. Your first example is not really a situation of nested quotes.
Option Explicit
Sub NestedQuotes()
Const s As String = "I say ""Did you know that she said """"Hi there!"""""""
Dim COL As Collection
Dim Start As Long, Length As Long, sTemp As String, V As Variant
Set COL = New Collection
sTemp = s
COL.Add sTemp
Do Until InStr(sTemp, Chr(34)) = 0
sTemp = COL(COL.Count)
sTemp = Replace(sTemp, String(2, Chr(34)), String(1, Chr(34)))
Start = InStr(sTemp, Chr(34)) + 1
Length = InStrRev(sTemp, Chr(34)) - Start
sTemp = Mid(sTemp, Start, Length)
COL.Add sTemp
Loop
For Each V In COL
Debug.Print V
Next V
End Sub
My Solution
I spent some more time thinking and came up with this solution.
Function sMineDoubleQuoteHierarchy(s As String) As String
'Check the number of quotes in the string are even - sanity check
If (Len(s) - Len(Replace(s, """", ""))) Mod 2 <> 0 Then sMineDoubleQuoteHierarchy = "Error - Odd number of quotes found in sMineDoubleQuoteHierarchy() function": Exit Function
'First thing to do is find the first and last *single* quote in the string
Dim lStart, lEnd, i As Long, fs As String
lStart = InStr(1, s, """")
lEnd = InStrRev(s, """")
'After these have been found we need to remove them.
s = Mid(s, lStart + 1, lEnd - lStart - 1)
'Start at the first character
i = 1
Do While True
'Find where the next double quote is
i = InStr(1, s, """""")
'if no double quote is found then concatenate with fs with the remainder of s
If i = 0 Then Exit Do
'Else add on the string up to the char before the ith quote
fs = fs & Left(s, i - 1)
'Replace the ith double quote with a single quote
s = Left(s, i - 1) & Replace(s, """""", """", i, 1)
'Increment by 1 (ensuring the recently converted double quote is no longer a single quote
i = i + 1
Loop
'Return fs
sMineDoubleQuoteHierarchy = s
End Function
What's going on in this solution?
The first part of the process is removing the first and last single quote from the string and returning the text between them. Then we loop through the string replacing each instance of "" and replacing it with ". Each time we do this we skip to the next character to unsure strings like """" go to "" instead of ".
Does anyone else have a better/more compact solution?
Edit
After all the suggestions in this forum I settled with this. It's got some extra error trapping to find validate nested strings.
Public Function DoubleQuoteExtract(ByVal s As String, Optional ByRef ErrorLevel As Boolean) As String
'This effectively parses the string like BASIC does by removing incidents of "" and replacing them with "
'SANITY CHECK - Check even number of quotes
Dim countQuote As Double
countQuote = Len(s) - Len(Replace(s, """", ""))
'Calculate whether or not quote hierarchy is correct:
'"..." - Is okay - Count Quotes = 2 - Count Quotes / 2 = 1
'""..."" - Is not okay - Count Quotes = 4 - Count Quotes / 2 = 2
'"""...""" - Is okay - Count Quotes = 6 - Count Quotes / 2 = 3
'""""..."""" - Is not okay - Count Quotes = 8 - Count Quotes / 2 = 4
'etc.
'Ultimately: IF CountQuotes/2 = Odd The string hierarchy is setup fine
' IF CountQuotes/2 = Even, The string Hierarchy is setup incorrectly.
Dim X As Double: X = countQuote / 2
Dim ceil As Long: ceil = Int(X) - (X - Int(X) > 0)
If ceil Mod 2 <> 0 Then sDoubleQuoteExtract = "#Error - Incorrect number of double quotes forming an incomplete hierarchy.": GoTo ErrorOccurred
'If an odd number of quotes are found then they cannot be paired correctly, thus throw error
If countQuote Mod 2 <> 0 Then sDoubleQuoteExtract = "#Error - Odd number of quotes found in sMineDoubleQuoteHierarchy() function": GoTo ErrorOccurred
'Find the next incident of single quote. Trim the string to this
s = Mid(s, InStr(1, s, String(1, Chr(34))))
'replace all instances of "" with "
s = Replace(s, String(2, Chr(34)), String(1, Chr(34)))
'Finally trim off the first and last quotes
DoubleQuoteExtract = Mid(s, 2, Len(s) - 2)
ErrorLevel = False
Exit Function
ErrorOccurred:
ErrorLevel = True
End Function

Splitting address, city, state, and zip, lacking delimiters, in excel

I have an excel spreadsheet that contains entire addresses packed in a single cell without delimiters. The addresses look like this:
2701 NW 64TH TER MARGATE FL 33063-1703
901 NE 8 ST HALLANDALE BEACH FL 33009-2626
1840 DEWEY ST UNIT 305 HOLLYWOOD FL 33020
3049 NE 4 AVE WILTON MANORS FL 33334-2047
650 NE 56 CT OAKLAND PARK FL 33334-3528
So the first five cells in column A would contain the above addresses.
As you can see, some of the cities consist of two words but the state is always FL or NY. All I need to do is separate the address, city, state, and zip in their own columns. I'm hoping there's a way to do this in VBD (Visual Basic for Developers) in excel. So I can put it into a macro.
I have an idea of how it can be done, but my VBD is limited:
stateArray = Split("FL, NY")
cityArray = Split("Fort Lauderdale","Sunrise","Oakland Park")
For example, another programming language you might do something like this:
var arrStates, arrCities
arrCities = ["Fort Lauderdale", "Sunrise", "Oakland Park"]
arrStates = ["FL", "NY"]
var findAddress = function(curCity, curState){
for(var i=0; i < arrCities.length; i < arrStates.length; i--){
(arrCities[i] == curCity) ? arrCities[i] = CurCity : arrCities[i] = null;
(arrStates[i] == curState) ? arrStates[i] = curState : arrStates[i] = null;
}
if(arrCities[i] >= 0){
var city = arrCities[i];
}
if(arrStates[i] >= 0){
var state = arrStates[i];
}
createTable(city, state);
}
var createTable = function(city, state){
var tbl = document.createElement("Table");
var newRow = document.createElement("tr");
tbl.appendChild(newRow);
cols = [city, state];
for(var i=0; i < cols.length; i++){
var newCol = document.createElement("td");
newCol.innerText = cols[i];
newRow.appendChild(newCol);
}
}
Thanks for any response.
It seems that if you have to type out all the cities, you might as well just split all the cells manually. It may be easier to identify all the street types and use that as a delimiter. Note the spaces around the strings in the array.
Sub SplitAddresses()
Dim vaStates As Variant
Dim vaStreets As Variant
Dim i As Long
Dim rCell As Range
Dim sAddress As String
Dim sCity As String, sState As String
Dim sZip As String
Dim lStreetPos As Long, lStatePos As Long
vaStates = Array(" FL ", " NY ")
vaStreets = Array(" TER ", " ST ", " AVE ", " CT ")
For Each rCell In Sheet1.Range("A1:A5").Cells
sAddress = "": sCity = "": sZip = "": sState = ""
For i = LBound(vaStreets) To UBound(vaStreets)
lStreetPos = InStr(1, rCell.Value, vaStreets(i))
If lStreetPos > 0 Then
sAddress = Trim(Left$(rCell.Value, lStreetPos + Len(vaStreets(i)) - 1))
Exit For
End If
Next i
For i = LBound(vaStates) To UBound(vaStates)
lStatePos = InStr(1, rCell.Value, vaStates(i))
If lStatePos > 0 Then
sCity = Trim(Mid$(rCell.Value, Len(sAddress) + 1, lStatePos - Len(sAddress) - 1))
sState = Trim(Mid$(rCell.Value, lStatePos + 1, Len(vaStates(i)) - 1))
sZip = Trim(Mid$(rCell.Value, lStatePos + Len(vaStates(i)), Len(rCell.Value)))
Exit For
End If
Next i
rCell.Offset(0, 1).Value = "'" & sAddress
rCell.Offset(0, 2).Value = "'" & sCity
rCell.Offset(0, 3).Value = "'" & sState
rCell.Offset(0, 4).Value = "'" & sZip
Next rCell
End Sub
In situations like this I try to forget that I'm programming, and just think about what sort of thought processes I would use to figure out what each was normally.
2701 NW 64TH TER MARGATE FL 33063-1703
901 NE 8 ST HALLANDALE BEACH FL 33009-2626
1840 DEWEY ST UNIT 305 HOLLYWOOD FL 33020
3049 NE 4 AVE WILTON MANORS FL 33334-2047
650 NE 56 CT OAKLAND PARK FL 33334-3528
At 1st things may seem hectic, but if you look closer there are patterns.
The addresses all start with a set of #s as the start of the street address
The street address always ends in a street type abbreviation
If there is a unit of the building it is after the street address
The addresses all end with the zip code
Before the zip code is the state abbreviation
The City name is smack dab in the middle for the taking if everything else is stripped away.
This makes the pattern as follows
Street # : Street Type : Unit {Optional} : City : State: Zip Code
Strip each piece off of a temporary string variable using string functions and you should be able to rebuild it fairly easily.
Hope that helps.
Here is some VBA code to get you started: you would need to add error handling
Option Explicit
Option Compare Text
Sub SplitAddress()
Dim vStates As Variant
Dim vCities As Variant
Dim vInput As Variant
Dim vAddress() As Variant
Dim j As Long
Dim str1 As String
' States/Cities/Inputs are named ranges containing the data
vStates = [States]
vCities = [Cities]
vInput = [Inputs]
ReDim vAddress(1 To UBound(vInput) - LBound(vInput) + 1, 1 To 4)
For j = 1 To UBound(vInput)
str1 = Trim(CStr(vInput(j, 1)))
If Len(str1) = 0 Then Exit For
FindSplit j, 3, str1, vStates, vAddress()
FindSplit j, 2, str1, vCities, vAddress()
Next j
ActiveSheet.Range("A2").Resize(UBound(vAddress), UBound(vAddress, 2)) = vAddress
End Sub
Sub FindSplit(j As Long, k As Long, str1 As String, vItems As Variant, vAddress() As Variant)
Dim iPos As Long
Dim jItem As Long
Dim strItem As String
For jItem = 1 To UBound(vItems)
strItem = Trim(CStr(vItems(jItem, 1)))
iPos = InStr(str1, " " & strItem & " ")
If iPos > 0 Then
vAddress(j, k) = Mid(str1, iPos + 1, Len(strItem))
If k = 3 Then
vAddress(j, k + 1) = Right(str1, Len(str1) - (iPos + 3))
str1 = Left(str1, iPos)
Else
vAddress(j, 1) = Left(str1, iPos - 1)
End If
Exit For
End If
Next jItem
End Sub

Resources