I was helping in the Microsoft Answers Forum today:
and thought I’d share the solution here as I’ve seen similar questions in the past.
Basically, the user had a string, any string, and wanted to extract all the phone numbers from it. The phone numbers, originally, were of the 000-000-0000 format.
I knew the best approach would be to use a regular expression (RegEx) and I remembered that a while back I helped another forum user with a similar question regarding extracting e-mail addresses from a string and so I thought that it would give me a great starting point to build from. So, I turned towards my prior post
Returning an Array of Values
With that in hand, it was then just a question of building the appropriate pattern for the RegEx. Now there are tons of variations that could work, some more complete than others, but below is what I ended up testing which worked for this specific scenario.
'---------------------------------------------------------------------------------------
' Procedure : ExtractEmailAddresses
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Extract phone numbers from a supplied string
' Returns an array of the phone numbers
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
' Reference : https://www.devhut.net/vba-extract-email-addresses-from-a-string/
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sInput : String to parse/extract phone numbers from
'
' Usage:
' ~~~~~~
' See TestMe Sub
'
' Revision History:
' Rev Date(yyyy/mm/dd) Description
' **************************************************************************************
' 1 2021-12-07 Initial Release, Forum Help
'---------------------------------------------------------------------------------------
Public Function ExtractPhoneNo(ByVal sInput As Variant) As Variant
On Error GoTo Error_Handler
Dim oRegEx As Object
Dim oMatches As Object
Dim oMatch As Object
Dim sPhoneNo As String
If Not IsNull(sInput) Then
Set oRegEx = CreateObject("VBScript.RegExp")
With oRegEx
.Pattern = "([0-9]{3}-[0-9]{3}-[0-9]{4})"
.Global = True
.IgnoreCase = True
.MultiLine = True
Set oMatches = .Execute(sInput)
End With
For Each oMatch In oMatches
sPhoneNo = oMatch.Value & "," & sPhoneNo
Next oMatch
If Right(sPhoneNo, 1) = "," Then sPhoneNo = Left(sPhoneNo, Len(sPhoneNo) - 1)
ExtractPhoneNo = Split(sPhoneNo, ",") 'Return an array of email addresses extracted from sInput
Else
ExtractPhoneNo = Null
End If
Error_Handler_Exit:
On Error Resume Next
If Not oMatch Is Nothing Then Set oMatch = Nothing
If Not oMatches Is Nothing Then Set oMatches = Nothing
If Not oRegEx Is Nothing Then Set oRegEx = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occured" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: ExtractPhoneNo" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
and an example of its usage could be:
Sub Test()
Dim aPhoneNos As Variant
Dim i As Long
aPhoneNos = ExtractPhoneNo("555-555-1001, 555-555-1002, X1E-D2SQ, 555-554-3411, SWQ-21AK, 555-554-5212")
For i = 0 To UBound(aPhoneNos)
Debug.Print i + 1, aPhoneNos(i)
Next i
End Sub
Running the above outputs:
1 555-554-5212 2 555-554-3411 3 555-555-1002 4 555-555-1001
This approach can be great if you wish to iterate over the result to push them to a table, use the values to populate a combo box/listbox, … or perform some specific action on each value.
Returning a Delimited List
What if you wanted a delimited list, rather than an array that you need to iterate through? Well, nothing could be easier!
'---------------------------------------------------------------------------------------
' Procedure : ExtractEmailAddresses
' Author : Daniel Pineault, CARDA Consultants Inc.
' Website : http://www.cardaconsultants.com
' Purpose : Extract phone numbers from a supplied string
' Returns a Delimited string of the phone numbers
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
' (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
' Reference : https://www.devhut.net/vba-extract-email-addresses-from-a-string/
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sInput : String to parse/extract phone numbers from
' sDelim : Delimiter to use to separate the values with
'
' Usage:
' ~~~~~~
' ? ExtractDelimPhoneNo("555-555-1001, 555-555-1002, X1E-D2SQ, 555-554-3411, SWQ-21AK, 555-554-5212")
' Returns -> 555-554-5212,555-554-3411,555-555-1002,555-555-1001
' ? ExtractDelimPhoneNo("555-555-1001, 555-555-1002, X1E-D2SQ, 555-554-3411, SWQ-21AK, 555-554-5212", "~!")
' Returns -> 555-554-5212~!555-554-3411~!555-555-1002~!555-555-1001
' ? ExtractDelimPhoneNo("555-555-1001, 555-555-1002, X1E-D2SQ, 555-554-3411, SWQ-21AK, 555-554-5212", vbCrLf)
' Returns -> 555-554-5212
' 555-554-3411
' 555-555-1002
' 555-555-1001
'
' Revision History:
' Rev Date(yyyy/mm/dd) Description
' **************************************************************************************
' 1 2021-12-07 Initial Release, Forum Help
'---------------------------------------------------------------------------------------
Public Function ExtractDelimPhoneNo(ByVal sInput As Variant, Optional ByVal sDelim As String = ",") As String
On Error GoTo Error_Handler
Dim oRegEx As Object
Dim oMatches As Object
Dim oMatch As Object
Dim sPhoneNo As String
If Not IsNull(sInput) Then
Set oRegEx = CreateObject("VbScript.RegExp")
With oRegEx
.Pattern = "([0-9]{3}-[0-9]{3}-[0-9]{4})"
.Global = True
.IgnoreCase = True
.MultiLine = True
Set oMatches = .Execute(sInput)
End With
For Each oMatch In oMatches
sPhoneNo = oMatch.Value & sDelim & sPhoneNo
Next oMatch
If sPhoneNo <> "" Then sPhoneNo = Left(sPhoneNo, Len(sPhoneNo) - Len(sDelim))
ExtractDelimPhoneNo = sPhoneNo
Else
ExtractDelimPhoneNo = ""
End If
Error_Handler_Exit:
On Error Resume Next
If Not oMatch Is Nothing Then Set oMatch = Nothing
If Not oMatches Is Nothing Then Set oMatches = Nothing
If Not oRegEx Is Nothing Then Set oRegEx = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occured" & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: ExtractDelimPhoneNo" & vbCrLf & _
"Error Description: " & Err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
, vbOKOnly + vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
This approach is great for when you simply wish to build a single string for use in queries/reporting in which you want all the values concatenated together.
A Final Word On The Subject
Never forget that the beauty of RegEx is that if your phone numbers are in a different format, it’s just a question of adjusting the RegEx pattern to one that suits your needs (add parenthesis, make characters optional, …).
Also, as I’ve mentioned in other posts, the web is filled with sites with sample patterns. So before reinventing the wheel perform a quick search as someone has probably already done what it is you are trying to do and you may be able to save yourself considerable time and frustration by simply adopting their pattern.
As you can see, it is very easy parse a string and extract all the phone numbers.
I hope this helps a few people out there.
Hi Daniel. I am the one you helped on this. I tried to modify this and use it on something else. I have a string that can have 3 or 4 numbers that I need to do the same thing with.
I set pattern to this .Pattern = “([0-9]{4})” and was able to grab the 4 character numbers. When I set it to three it was still pulling in the 4, but with only 3 characters. Is there a way to do both? Notice the , and spaces can be different as well. Garbage data in, garbage data out.
Example:
232,4211, 135,412,1153, 146
Results:
232
4211
135
412
1153
146