This is a sample data contained in one cell:
2014/08/19 12:59 John Doe
add sample#hotmail.com
I need to extract the name in the text. I know that it is always placed after the datetime stamp.
My idea is to find the position of ":" and add 4 thus getting the position of the first letter of the first name:
colonLoc = InStr(sampleData, ":")
firstLetterLoc = colonLoc + 4
How can I get the first and last name after that?
Here is a one liner to achieve what you want.
debug.print Mid(Split(Split(Range("A1").Value, Chr(10))(0), ":")(1), 3)
EDIT:
Actually you don't need VBA for this. You can use Excel formulas as well
=MID(A1,FIND(":",A1)+3,FIND(CHAR(10),A1)-(FIND(":",A1)+3))
This works even for names with spaces:
Function ExtractName(str As String) As String
Dim i As Long
Dim splitStr() As String
Dim nameParts() As String
splitStr = Split(str, " ")
ReDim nameParts(LBound(splitStr) To UBound(splitStr) - 4)
For i = LBound(nameParts) To UBound(nameParts)
nameParts(i) = splitStr(i + 2)
Next i
ExtractName = Join(nameParts, " ")
End Function
What this effectively does is remove four substrings: the date, the time, the add bit, and the e-mail address. Everything else in the middle is assumed to be part of the name.
Example usage:
Debug.Print ExtractName("2014/08/19 12:59 John Doe add sample#hotmail.com")
Debug.Print ExtractName("2014/08/19 12:59 Johan Sebastian Bach add sample#hotmail.com")
Debug.Print ExtractName("2014/08/19 12:59 Fuh Wei Guo Tang add sample#hotmail.com")
Debug.Print ExtractName("2014/08/19 12:59 Jens von dem Hagen add sample#hotmail.com")
Debug.Print ExtractName("2014/08/19 12:59 José Manuel de Santiago Itthuralde add sample#hotmail.com")
EDIT Now you say your input string is split over two lines... This works for me with the input you specify:
Function ExtractName(str As String) As String
Dim i As Long
Dim splitStr() As String
Dim nameParts() As String
splitStr = Split(Split(str, vbLf)(0), " ")
ReDim nameParts(LBound(splitStr) To UBound(splitStr) - 2)
For i = LBound(nameParts) To UBound(nameParts)
nameParts(i) = splitStr(i + 2)
Next i
ExtractName = Join(nameParts, " ")
End Function
It's like this:
Option Explicit
Public Sub Playground()
Const SampleData As String = "2014/08/19 12:59 John Doe add sample#hotmail.com"
Dim Parts() As String
Dim FirstName As String
Dim LastName As String
Parts = Split(SampleData)
FirstName = Parts(2)
LastName = Parts(3)
Debug.Print FirstName
Debug.Print LastName
End Sub
For more complicated cases (e.g. spaces in names) you might have to tweak it a little bit.
This will give you firstname (assuming there is only 1), lastname (all other names) and email in a variant array
Option Explicit
Public Function Name(source As String) As Variant
Dim breakup As Variant
breakup = Split(source, ":")
breakup = Split(Mid(breakup(1), 4), " ")
Dim i As Integer
Dim FirstName As String
FirstName = breakup(0)
Dim LastName As String
For i = 1 To UBound(breakup) - 2
LastName = LastName & " " & breakup(i)
Next
LastName = Mid(LastName, 2)
Dim Email As String
Email = breakup(UBound(breakup))
Name = Array(FirstName, LastName, Email)
End Function
sampleData = "2014/08/19 12:59 John Doe add sample#hotmail.com"
New_String = Split(sampleData)
sName = New_String(2) & " " & New_String(3)
Debug.Print sName
Easy as that :)
Related
How do I parse multiple values out of a single column?
The problem is that multiple values are surrounded by extraneous (for my purposes) data.
Example:
Select * from my_table:
Fname Lname Data
Fred Smith #3aXXXX;Name:AA;#43deXXXX;Name:BB;#5433ed9;NAME:ABC;*#!XXXXXXXX;NAME:MyPetDog;##IDXXXX
For the Data column, I want to extract all the values following the "Name:" fields from the column. That would be the text following "Name:" and preceding ";". In the example above:
Select Fname, Lname, [DATA] from my_table
Fname Lname [*Parsed* DATA]
Fred Smith AA,BB, ABC, MyPetDog
Solving the above Would be a tremendous help. However, what I would really like to do a lookup/replace (SWITCH, etc.) each of the values returned from the string:
Fname Lname [Translated DATA]
Fred Smith Airport, Bus Station, Restaurant, FIDO
I apologize for using notional data. My actual script (on another network) involves several table joins to get to the column DATA. I just can't figure out how to extract the specific values from this large string (other that to extract the full data set and use AWk or MS Excel to cleanup the data afterwards).
Appreciate any assistance or tips on solving this.
Kevin L.
I would recommend creating a small VBA function that takes the "ugly" data and splits it out using the Split function. Something like:
Public Function fSplitData(strData As String) As String
Dim aData() As String
Dim lngLoop1 As Long
aData = Split(strData, ";")
For lngLoop1 = LBound(aData) To UBound(aData)
If Left(aData(lngLoop1), 5) = "Name:" Then
fSplitData = fSplitData & Mid(aData(lngLoop1), 6) & ","
End If
Next lngLoop1
If Right(fSplitData, 1) = "," Then fSplitData = Left(fSplitData, Len(fSplitData) - 1)
End Function
This gives the required output of:
AA,BB,ABC,MyPetDog
And, rather than just concatenating the extracted value, you could use a recordset to get the data from a lookup table. In your case, as you only have 8 values, you could just use If within the code:
Public Function fSplitData(strData As String) As String
Dim strLookup As String
Dim aData() As String
Dim lngLoop1 As Long
aData = Split(strData, ";")
For lngLoop1 = LBound(aData) To UBound(aData)
If Left(aData(lngLoop1), 5) = "Name:" Then
strLookup = Mid(aData(lngLoop1), 6)
If strLookup = "AA" Then
fSplitData = fSplitData & "Airport,"
ElseIf strLookup = "BB" Then
fSplitData = fSplitData & "Bus Station,"
ElseIf strLookup = "ABC" Then
fSplitData = fSplitData & "Restaurant,"
ElseIf strLookup = "MyPetDog" Then
fSplitData = fSplitData & "FIDO,"
End If
End If
Next lngLoop1
If Right(fSplitData, 1) = "," Then fSplitData = Left(fSplitData, Len(fSplitData) - 1)
End Function
You can then use this function in a query, just like you would use a standard Access function. So your SQL would look like:
SELECT
FName,
LName,
Data,
fSplitData([Data]) AS TranslatedData
FROM Table1;
Thanks to #Applecore, I have a almost working solution (though not likely the best solution):
SELECT Fname,
Lname,
SWITCH(data like "*AA*","Airport")&", "&
SWITCH(data like "*BB*", "Bus Station")&", "&
SWITCH(data like "*ABC*", "Restaurant")&", "&
SWITCH(data like "*MyPetDog*","FIDO") as DATA
Fname Lname [Translated DATA]
Fred Smith Airport, Bus Station, Restaurant, FIDO
The only problem is,if a value is NOT there, then I get extra commas. For example, if BB is the only value present, then I get:
Fname Lname [Translated DATA]
Fred Smith , Bus Station, ,
Do as #AppleCore suggests, use an external function to avoid the mess.
SELECT
Fname,
Lname,
CleanField([Data]) AS TranslatedData
FROM
my_table;
Copy-paste the function (using Select Case .. for the conversion) into a new module, go to menu Debug, Compile, and save the module as, say, Module1_:
Public Function CleanField(ByVal Value As String) As String
Dim Parts As Variant
Dim Index As Integer
Dim Part As String
Dim Text As String
Parts = Split(";" & Value, ":")
For Index = LBound(Parts) To UBound(Parts)
Part = Split(Parts(Index), ";")(0)
Select Case Part
Case Is = "AA"
Part = "Airport"
Case Is = "BB"
Part = "Bus station"
Case Is = "ABC"
Part = "Restaurant"
Case Is = "MyPetDog"
Part = "FIDO"
End Select
If Part <> "" Then
If Text <> "" Then
Text = Text & ", "
End If
Text = Text & Part
End If
Next
CleanField = Text
End Function
Example:
Fname Lname TranslatedData
------- ------- --------------------------------------
Fred Smith Airport, Bus station, Restaurant, FIDO
George Olsen Airport, Restaurant, Bus station, FIDO
Tina Doe Restaurant, Bus station, FIDO
I have a formula to swap last names with first names in cells where the format is "Smith, John".
=MID(A4&" "&A4,(FIND(" ",A4)+1),(LEN(A4)-1))
I created a function to utilize this functionality and it seemed to work at first. The function is:
Function SwapNames(text As String) As String
SwapNames = Mid(text & " " & text, (Find(" ", text) - 1, (Len(text) - 1))
End Function
I converted my workbook to an Add-In filetype so I could use this globally and now it says the Find function is undefined. What am I doing wrong here?
As #Nathan_Sav said - use split, and perhaps an optional argument to identify the delimiter.
So =swapnames("Bartrup-Cook Darren") returns "Darren Bartrup-Cook" and =swapnames("Bartrup-Cook Darren","-") returns "Cook Darren Bartrup" a #REF! error is returned if the delimiter isn't present in the string.
Function SwapNames(text As String, Optional Delimiter As String = " ") As Variant
Dim SplitAt As Long
Dim NamePart As Variant
SplitAt = InStr(text, Delimiter)
If SplitAt = 0 Then
SwapNames = CVErr(xlErrRef)
Else
NamePart = Split(text, Delimiter)
SwapNames = NamePart(1) & " " & NamePart(0)
End If
End Function
This is how you can use Split function and swap the name.
Function SwapNames(text As String) As String
SwapNames = Trim(Split(text, ",")(1)) & " " & Trim(Split(text, ",")(0))
End Function
So it will change Smith, John to John Smith and Smith, John J to John J Smith.
To be more specific than the title... here is one example of a string to use: "You have received 25 dollars from John Doe" I need nameDonated to get just the name John or John Doe depending on if the string has first name or first and last name. Below is the code I have showing John Doe in the string but it only gets John and not the full name John Doe. I am using Visual Basic 2010. Can anyone help?
Dim myString As String = "You have received 25 dollars from John Doe"
Dim fields() As String = myString.Split(" ")
Dim numberDollars As String = fields(3).Substring(0)
Dim nameDonated As String = fields(6).Substring(0)
' outputs John donated 25 dollars
TextBox1.Text = nameDonated & " donated " & numberDollars & " dollars."
Since it's always in the same format, "You have received x dollars from y", you can split the string based on that format.
Dim myString As String = "You have received 25 dollars from John Doe"
' split into {"You have received 25 dollars", "John Doe"}
Dim mySplitString1 As String() = myString.Split(New String() {" from "}, 0)
' and take the second item which has the name
Dim donorName As String = mySplitString1(1)
' then split the first item into {"You", "have", "received", "25", "dollars"}
Dim mySplitString2 As String() = mySplitString1(0).Split(" ")
' and take the fourth item which has the amount
Dim dollarAmount As Single = Single.Parse(mySplitString2(3))
TextBox1.Text = String.Format("{0} donated {1:0} dollars", donorName, dollarAmount)
Sometimes the simplest answer is the best. Using your original code, change the name assignment to
Dim nameDonated As String = fields(6) & If(fields.Length = 8, " " & fields(7), "")
Lets say I have a text Howard Johnson, 21 (USA)
I want to get the substring of the text Johnson.
I could do this with InStr and Microsoft.VisualBasic.Left Or Mid, But I always found this method rather tedious and I want to know if there is another easier method to do this.
Dim myText As String = "Howard Johnson, 21 (USA)"
Dim textIWant As String = InStr(1, myText, Chr(32))
Dim LastName As String = Mid(myText, textIWant + 1, textIWant)
'Output: Johnson
Any suggestions?
Try this code - it uses the IndexOf function of a String to locate the first instance of a character within that String.
For a surname, the example code is looking for the first space and the first comma and taking the text in between. The assumption is that the surname is always delimited that way.
For the country, the example code is looking for the first ( and the last ) and taking the text in between. The assumption is that the country is always in round brackets.
Here's the code:
Sub Main()
Dim Input As String
Dim Surname As String
Dim Country As String
Input = "Howard Johnson, 21 (USA)"
Surname = Input.Substring(Input.IndexOf(" ") + 1, Input.IndexOf(",") - Input.IndexOf(" ") - 1)
Country = Input.Substring(Input.IndexOf("(") + 1, Input.IndexOf(")") - Input.IndexOf("(") - 1)
Console.WriteLine(Surname)
Console.WriteLine(Country)
Console.ReadKey()
End Sub
It will also work for people who have spaces in their surname e.g.:
Input = "Albert del Rosario, 75 (Phillipines)"
Surname = Input.Substring(Input.IndexOf(" ") + 1, Input.IndexOf(",") - Input.IndexOf(" ") - 1)
Will output
del Rosario
Dim myText = "Howard Johnson, 21 (USA)"
Dim LastName = myText.Split(" "c, ","c)(1) ' myText.Split(" "c, ","c) gives array {"Howard", "Johnson", "", "21", "(USA)"}
I have a list of full names in a column like for example:
Dave M. Butterworth
Dave M. Butterworth,II
H.F. Light jr
H.F. Light ,jr.
H.F. Light sr
Halle plumerey
The names are in a column. The initials are not limited to these only.
I want to extract the last name using a generic function. Is it possible?
Consider the following UDF:
Public Function LastName(sIn As String) As String
Dim Ka As Long, t As String
ary = Split(sIn, " ")
Ka = UBound(ary)
t = ary(Ka)
If t = "jr" Or t = ",jr" Or t = "sr" Or t = ",jr." Then
Ka = Ka - 1
End If
t = ary(Ka)
If InStr(1, t, ",") = 0 Then
LastName = t
Exit Function
End If
bry = Split(t, ",")
LastName = bry(LBound(bry))
End Function
NOTE:
You will have to expand this line:
If t = "jr" Or t = ",jr" Or t = "sr" Or t = ",jr." Then
to include all other initial sets you wish to exclude.You will also have to update this code to handle other exceptions as you find them !
Remove punctuation, split to an array and walk backwards until you find a string that does not match a lookup of ignorable monikers like "ii/jr/sr/dr".
You could also add a check to eliminate tokens based on their length.
Function LastName(name As String) As String
Dim parts() As String, i As Long
parts = Split(Trim$(Replace$(Replace$(name, ",", ""), ".", "")), " ")
For i = UBound(parts) To 0 Step -1
Select Case UCase$(parts(i))
Case "", "JR", "SR", "DR", "I", "II"
Case Else:
LastName = parts(i)
Exit Function
End Select
Next
End Function