How-to Extract All The URLs From a String

I was helping out in a forum discussion in which a developer was asking for assistance in getting a listing of URLs found within a string of text and thought I’d share here the solution(s) I came up with as I’m sure he’s not the first, nor the last to need to do this type of thing.
 

Regular Expressions (RegEx) to the Rescue

Right off the bat, I knew the simplest solution, when we talking about working with patterns (in our case http(s)://www…), would be to use Regular Expressions (RegEx). So I came here to my blog, pulled up one of my existing routines, tweaked the code, replaced the pattern et voilà! The result was:

'---------------------------------------------------------------------------------------
' Procedure : ExtractURLs
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Extract a list of URL from a string
' 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: Early Binding -> Microsoft VBScript Regular Expressions X.X
'             Late Binding  -> None required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sInput    : The string to extract a listing of URLs from
' sSeparator: String to be used as a separator between match values ",", ", ", VbCrLf
'
' Returns:
' ~~~~~~~~~~~~~~~~
' String of matches
'
' Revision History:
' Rev       Date(yyyy-mm-dd)        Description
' **************************************************************************************
' 1         2025-06-04              Forum Help
'---------------------------------------------------------------------------------------
Function ExtractURLs(ByVal sInput As String, _
                     Optional sSeparator As String = ",") As String
    On Error GoTo Error_Handler
    #Const RegEx_EarlyBind = False   'True => Early Binding / False => Late Binding
                                     ' Normally this should be a module level variable
    #If RegEx_EarlyBind = True Then
        Dim oRegEx            As VBScript_RegExp_55.RegExp
        Dim oMatches          As VBScript_RegExp_55.MatchCollection

        Set oRegEx = New VBScript_RegExp_55.RegExp
    #Else
        Dim oRegEx            As Object
        Dim oMatches          As Object

        Set oRegEx = CreateObject("VBScript.RegExp")
    #End If
    Dim sResult               As String
    Dim iCounter              As Integer

    With oRegEx
        .Global = True
        .IgnoreCase = True
        .Pattern = "(https?://[^\s,]+|www\.[^\s,]+|\b[\w-]+\.[a-z]{2,}(?:/[^\s,]*)?)"
    End With

    If oRegEx.Test(sInput) Then
        Set oMatches = oRegEx.Execute(sInput)
        For iCounter = 0 To oMatches.Count - 1
            sResult = sResult & oMatches(iCounter).Value
            If iCounter < oMatches.Count - 1 Then
                sResult = sResult & sSeparator
            End If
        Next iCounter
    End If

    ExtractURLs = sResult

Error_Handler_Exit:
    On Error Resume Next
    Set oMatches = Nothing
    Set oRegEx = Nothing
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Source: ExtractURLs" & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Description: " & Err.Description & _
           Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
           , vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

 

Pure VBA Solution

With the fears of RegEx going the way of the Dodo thanks to Microsoft phasing out VBScript in the coming years and not explicitly explaining the implications on libraries such as FSO, RegEx, …, I thought I’d also briefly explore trying to do the same thing, but using pure VBA. As such, I came up with the following function:

'---------------------------------------------------------------------------------------
' Procedure : ExtractURLs
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Extract a list of URL from a string
' 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: None required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sInput    : The string to extract a listing of URLs from
' sSeparator: String to be used as a separator between match values ",", ", ", VbCrLf
'
' Returns:
' ~~~~~~~~~~~~~~~~
' String of matches
'
' Revision History:
' Rev       Date(yyyy-mm-dd)        Description
' **************************************************************************************
' 1         2025-06-04              Forum Help
'---------------------------------------------------------------------------------------
Function ExtractURLs(ByVal sInput As String, _
                     Optional sSeparator As String = ",") As String
    On Error GoTo Error_Handler
    Dim colURLs               As Collection
    Dim aElements()           As String
    Dim sElement              As String
    Dim lCounter              As Long

    Set colURLs = New Collection      ' Used to avoid duplicates
    aElements = Split(sInput, " ")    ' Split string on spaces

    For lCounter = LBound(aElements) To UBound(aElements)
        sElement = aElements(lCounter)    ' Individual word/element

        ' Remove trailing punctuation
        Do While Len(sElement) > 0 And InStr(".,;:!?)""", Right(sElement, 1)) > 0
            sElement = Left(sElement, Len(sElement) - 1)
        Loop

        ' Check if the Element is a URL or not
        If LCase(Left(sElement, 7)) = "http://" Or _
           LCase(Left(sElement, 8)) = "https://" Or _
           LCase(Left(sElement, 4)) = "www." Then
            colURLs.Add sElement, sElement
        End If
    Next lCounter

    ' ***** An alternative would be to simply return the Collection here *****

    ' Build CSV string
    If colURLs.Count > 0 Then
        For lCounter = 1 To colURLs.Count
            If ExtractURLs <> "" Then _
               ExtractURLs = ExtractURLs & sSeparator
            ExtractURLs = ExtractURLs & colURLs(lCounter)
        Next lCounter
    End If

Error_Handler_Exit:
    On Error Resume Next
    Set colURLs = Nothing
    Exit Function

Error_Handler:
    If Err.Number = 457 Then
        'This key is already associated with an element of this collection
        'Duplicate URL
        Resume Next
    Else
        MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
               "Error Source: ExtractURLs" & vbCrLf & _
               "Error Number: " & Err.Number & vbCrLf & _
               "Error Description: " & Err.Description & _
               Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
               , vbOKOnly + vbCritical, "An Error has Occurred!"
        Resume Error_Handler_Exit
    End If
End Function

 

Usage Example

Both functions are built in the exact same manner. You supply a text, specify the separator to use if other than a comma and it returns string of URLs found. For instance:

? ExtractURLs("How can I improve my writing skills see https://writingtips.com and https://grammarbook.com")

which outputs

https://writingtips.com,https://grammarbook.com

Or, if you prefer you can do:

? ExtractURLs("How can I improve my writing skills see https://writingtips.com and https://grammarbook.com", VbCrLf)

which outputs

https://writingtips.com
https://grammarbook.com

 
 
So there you have it, a couple quick ways to extract a list of URLs from a string using either RegEx or plain vanilla VBA.

2 responses on “How-to Extract All The URLs From a String

  1. John F Clark

    Excellent contribution Daniel! I appreciate the RegEx example and, not knowing what the future holds for VBScript/RegEx, REALLY appreciate that you offered a VBA alternative.

    1. Daniel Pineault Post author

      Yes, it unnerving not truly knowing what the changes will impact.

      I asked about it in a public post made by 2 of the leads on this (when the original announcement was made), even followed up through private channels and nothing. They simply will not give a simple Yes or No regarding which dll, vba libraries will be impacted so we can prepare.

      This is VERY typical of Microsoft. I don’t get it, but it is simply par for the course.

      Just more of that great ‘Support’ some MVPs love to always talk about!