Access

Cómo extraer todas las URL de una cadena

Estaba ayudando en una discusión en el foro en la que un desarrollador estaba pidiendo ayuda para obtener una lista de URL que se encuentran dentro de una serie de texto y pensé en compartir aquí las soluciones que se me ocurrió, ya que estoy seguro de que no es el primero, ni el último en necesitar hacer este tipo de cosas.

Expresiones regulares (regex) al rescate

De inmediato, sabía que la solución más simple, cuando hablamos de trabajar con patrones (en nuestro caso http (s): // www …), sería usar expresiones regulares (regex). Así que vine aquí a mi blog, tomé una de mis rutinas existentes, modificé el código, reemplazé el patrón et voilà! El resultado fue:

'---------------------------------------------------------------------------------------
' Procedure : ExtractURLs
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : 
' 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) - 
' 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

Solución pura de VBA

Con el temor de que Regex avance el camino del dodo gracias a que Microsoft elimine a VBScript en los próximos años y no explique explícitamente las implicaciones en bibliotecas como FSO, Regex, …, pensé que también explorar brevemente tratar de hacer lo mismo, pero usar VBA puro. Como tal, se me ocurrió la siguiente función:

'---------------------------------------------------------------------------------------
' Procedure : ExtractURLs
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : 
' 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) - 
' 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)) = " Or _
           LCase(Left(sElement, 8)) = " 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

Ejemplo de uso

Ambas funciones están construidas exactamente de la misma manera. Proporciona un texto, especifica el separador para usar si no sea una coma y devuelve una cadena de URL encontradas. Por ejemplo:

? ExtractURLs("How can I improve my writing skills see  and 

que sale

,

O, si lo prefiere, puede hacer:

? ExtractURLs("How can I improve my writing skills see  and  VbCrLf)

que sale

Así que ahí lo tienes, un par de formas rápidas de extraer una lista de URL de una cadena usando regex o vBa de vainilla simple.

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba