Option Strict Off
Imports System.Runtime.CompilerServices
Imports System.Linq.Expressions
Imports System.Text.RegularExpressions
Imports tsl5.ValidarDocumentoIdentidad
Imports System.Globalization
Imports System.Text

Namespace codificacion
    Public Class Caracteres
        Public Shared juegos()() As Char = New Char()() {"ñÑºªçÇáéíóúÁÉÍÓÚàèìòùÀÈÌÒÙâêîôûÂÊÎÔÛäëïöüÄËÏÖÜ¡", "·¶úùµ´ÄÅÕÆÇàÜåçíÈÉÙÊË¡£æè­ÀÁÑÂÃ¢¤¦ß®ÌÍÝÎÏØ¥§ÚÛ¸", "·¶úùµ´aeiouAEIOUÈÉÙÊË¡£æè­ÀÁÑÂÃ¢¤¦ß®ÌÍÝÎÏØ¥§ÚÛ¸"}
        Public Enum JuegoCaracteres
            WINDOWS = 0
            ROMAN8 = 1
            ROMAN8_SIN_ACENTOS = 2
        End Enum
    End Class
End Namespace
Namespace Extensiones
    Public Module StringExtensions

        <Extension()>
        Public Function EsDNIValido(ByVal DNI As String) As Boolean
            Try
                Dim v As New ValidarDocumentoIdentidad(DNI)
                Return v.EsCorrecto
            Catch ex As Exception
                Return False
            End Try
        End Function
        <Extension()>
        Public Function EsCIFValido(ByVal DNI As String) As Boolean
            Try
                Return validateCif(DNI)
            Catch ex As Exception
                Return False
            End Try
        End Function
        <Extension()>
        Public Function TipoDocumentoIdentidad(ByVal DNI As String) As TiposDocumentosEnum
            Try
                Dim v As New ValidarDocumentoIdentidad(DNI)
                If v.EsCorrecto = False Then Throw New Exception("No es un documento de identidad correcto")
                Return v.TipoDocumento
            Catch ex As Exception
                Throw New Exception(ex.Message, ex)
            End Try
        End Function


        <Extension()>
        Public Function EsEmailValido(ByVal email As String) As Boolean
            Try
                email = email.NothingAVacio.Trim.ToLower
                If email.NothingAVacio = "" Then
                    Return False
                Else
                    Dim addr = New System.Net.Mail.MailAddress(email)
                    Return addr.Address = email
                End If
            Catch ex As Exception
                Return False
            End Try
        End Function
        <Extension()>
        Public Function EsListaEmailsValida(ByVal Listaemail As String) As Boolean
            Try
                If Listaemail.NothingAVacio = "" Then
                    Return False
                Else
                    Dim emails = Listaemail.Split(";")
                    For Each email In emails
                        email = email.NothingAVacio.Trim.ToLower
                        If email <> "" Then
                            Dim addr = New System.Net.Mail.MailAddress(email)
                            If addr.Address <> email Then
                                Throw New Exception("Email incorrecto")
                            End If
                        End If
                    Next
                    Return True
                End If
            Catch ex As Exception
                Return False
            End Try
        End Function

        <Extension()>
        Public Function EsNumeroTelefonoMovilEspañolValido(ByVal Telefono As String) As Boolean
            Telefono = Telefono.NothingAVacio.Trim
            Dim Valido As Boolean = True
            If Telefono.Length = 9 Then
                If Not (Telefono.StartsWith("6") Or Telefono.StartsWith("7")) Then
                    Valido = False
                End If
            ElseIf Telefono.Length = 11 Then
                If Not Telefono.StartsWith("34") Then
                    Valido = False
                End If
            ElseIf Telefono.Length = 12 Then
                If Not Telefono.StartsWith("+34") Then
                    Valido = False
                End If
            Else
                Valido = False
            End If
            If Valido Then
                For i = 1 To Telefono.Length - 1
                    If Not "1234567890".Contains(Telefono.Substring(i, 1)) Then
                        Valido = False
                        Exit For
                    End If
                Next
            End If
            Return Valido
        End Function
        <Extension()>
        Public Function EsNumeroTelefonoEspañolValido(ByVal Telefono As String) As Boolean
            Telefono = Telefono.NothingAVacio.Trim
            Dim Valido As Boolean = True
            If Telefono.Length = 9 Then
                If Not (Telefono.StartsWith("6") Or Telefono.StartsWith("7") Or Telefono.StartsWith("8") Or Telefono.StartsWith("9")) Then
                    Valido = False
                End If
            ElseIf Telefono.Length = 11 Then
                If Not Telefono.StartsWith("34") Then
                    Valido = False
                End If
            ElseIf Telefono.Length = 12 Then
                If Not Telefono.StartsWith("+34") Then
                    Valido = False
                End If
            Else
                Valido = False
            End If
            If Valido Then
                For i = 1 To Telefono.Length - 1
                    If Not "1234567890".Contains(Telefono.Substring(i, 1)) Then
                        Valido = False
                        Exit For
                    End If
                Next
            End If
            Return Valido
        End Function
        <Extension()>
        Public Function HoraDecimalASexagesimal(ByVal Cadena As String) As String
            If Cadena.Contains(".") Then
                Dim ParteDecimal = CInt(Cadena.Split(".")(1).PadRight(2, "0").Substring(0, 2))
                Dim Minutos = Math.Min(59, Math.Round(ParteDecimal * 60 / 100, 0, MidpointRounding.AwayFromZero))
                Return Cadena.Split(".")(0).PadLeft(2, "0") & ":" & Minutos.ToString.PadLeft(2, "0")
            Else
                Return Cadena.PadLeft(2, "0") & ":00"
            End If
        End Function



        <Extension()>
        Public Function HoraStringATimeSpan(ByVal Cadena As String) As TimeSpan
            Dim TS As TimeSpan
            If Cadena = "00:00" Then
                TS = New TimeSpan(0)
            Else
                Dim HoraEntera As String = Cadena
                If Cadena.StartsWith("-") Then HoraEntera = Cadena.Substring(1)
                If HoraEntera.Split(":").Length = 3 Then
                    TS = New TimeSpan(CInt(HoraEntera.Split(":")(0)), CInt(HoraEntera.Split(":")(1)), CInt(HoraEntera.Split(":")(2)))
                Else
                    TS = New TimeSpan(CInt(HoraEntera.Split(":")(0)), CInt(HoraEntera.Split(":")(1)), 0)
                End If
                If Cadena.StartsWith("-") Then
                    TS = -TS
                End If
            End If
            Return TS
        End Function

        <Extension()>
        Public Function ATimeSpan(ByVal Cadena As String) As TimeSpan
            Dim TS As TimeSpan
            If Cadena = "0" Then
                TS = New TimeSpan(0)
            Else
                Dim HoraEntera As String = Cadena
                If Cadena.StartsWith("-") Then HoraEntera = Cadena.Substring(1)
                If HoraEntera.Contains(".") Then
                    TS = New TimeSpan(CInt(HoraEntera.Split(".")(0)), (Double.Parse("0." & HoraEntera.Split(".")(1), Globalization.CultureInfo.InvariantCulture) * 60), 0)
                Else
                    TS = New TimeSpan(CInt(HoraEntera.Split(".")(0)), 0, 0)
                End If
                If Cadena.StartsWith("-") Then
                    TS = -TS
                End If
            End If
            Return TS
        End Function


        <Extension()>
        Public Function NothingAVacio(ByVal Cadena As String) As String
            If Cadena Is Nothing OrElse Cadena Is DBNull.Value Then
                Return ""
            Else
                Return Cadena
            End If
        End Function


        <Extension()>
        Public Sub ImprimirEnConsola(ByVal aString As String)
            Console.WriteLine(aString)
        End Sub

        <Extension()>
        Public Sub ImprimirEnConsolaDeDepuracion(ByVal aString As String)
            System.Diagnostics.Debug.WriteLine(aString)
        End Sub


        ''' <summary>
        ''' Acorta la longitud de un String hasta la longitud especificada.
        ''' </summary>
        ''' <param name="aString"></param>
        ''' <param name="longitud">La longitud a la que se desea acortar la cadena.</param>
        ''' <returns></returns>
        ''' <remarks>Si la cadena es más pequeña que la longitud especificada no lanza excepción. Siempre hace Trim a la cadena.</remarks>
        <Extension()>
        Public Function AcortarPorLaIzquierda(ByVal aString As String, ByVal longitud As Integer) As String
            If aString Is Nothing Then
                Return ""
            Else
                Dim resultado As String
                aString = aString.Trim
                If aString.Length >= longitud Then
                    resultado = aString.Substring(aString.Length - longitud, longitud).TrimEnd
                Else
                    resultado = aString
                End If
                Return resultado
            End If
        End Function

        ''' <summary>
        ''' Acorta la longitud de un String hasta la longitud especificada.
        ''' </summary>
        ''' <param name="aString"></param>
        ''' <param name="longitud">La longitud a la que se desea acortar la cadena.</param>
        ''' <returns></returns>
        ''' <remarks>Si la cadena es más pequeña que la longitud especificada no lanza excepción. Siempre hace Trim a la cadena.</remarks>
        <Extension()>
        Public Function Acortar(ByVal aString As String, ByVal longitud As Integer) As String
            If aString Is Nothing Then
                Return ""
            Else
                Dim resultado As String
                aString = aString.Trim
                If aString.Length >= longitud Then
                    resultado = aString.Substring(0, longitud).TrimEnd
                Else
                    resultado = aString
                End If
                Return resultado
            End If
        End Function
        ''' <summary>
        ''' Acorta la longitud de un String hasta la longitud especificada.
        ''' </summary>
        ''' <param name="aString"></param>
        ''' <param name="longitud">La longitud a la que se desea acortar la cadena.</param>
        ''' <returns></returns>
        ''' <remarks>Si la cadena es más pequeña que la longitud especificada no lanza excepción. Siempre hace Trim a la cadena.</remarks>
        <Extension()>
        Public Function AcortarNombreFichero(ByVal aString As String, ByVal longitud As Integer) As String
            If aString Is Nothing Then
                Return ""
            Else
                Dim resultado As String
                aString = aString.Trim
                If aString.Length >= longitud Then
                    Dim extension = IO.Path.GetExtension(aString)
                    Dim filename = IO.Path.GetFileNameWithoutExtension(aString)
                    longitud = longitud - extension.Length
                    resultado = aString.Substring(filename, longitud).TrimEnd & extension
                Else
                    resultado = aString
                End If
                Return resultado
            End If
        End Function
        <Extension()>
        Public Function LongitudFija(ByVal aString As String, ByVal longitud As Integer) As String
            If aString Is Nothing Then
                Return ""
            Else
                Dim resultado As String
                aString = aString.Trim
                If aString.Length >= longitud Then
                    resultado = aString.Substring(0, longitud)
                Else
                    resultado = aString.PadRight(longitud, " ")
                End If
                Return resultado
            End If
        End Function
        ''' <summary>
        ''' Acorta la longitud de un String hasta la longitud especificada. Nunca lanza excepciones, aunque no exista el objeto.
        ''' </summary>
        ''' <param name="aString"></param>
        ''' <param name="longitud">La longitud a la que se desea acortar la cadena.</param>
        ''' <returns></returns>
        ''' <remarks>Si la cadena es más pequeña que la longitud especificada no lanza excepción. Siempre hace Trim a la cadena. Nunca lanza excepciones, aunque no exista el objeto.</remarks>
        <Extension()>
        Public Function AcortarSinExcepciones(ByVal aString As String, ByVal longitud As Integer) As String
            Dim resultado As String
            Try
                aString = aString.Trim
                If aString.Length >= longitud Then
                    resultado = aString.Substring(0, longitud).TrimEnd
                Else
                    resultado = aString
                End If
            Catch ex As Exception
                resultado = ""
            End Try
            Return resultado
        End Function
        ''' <summary>
        ''' Recorta por el final de la cadena el número de caracteres especificado en "longitud".
        ''' </summary>
        ''' <param name="aString">La cadena a manipular.</param>
        ''' <param name="longitud">El número de caracteres que se desea recortar al final de la cadena.</param>
        ''' <returns>La cadena original pero con "longitud" caracteres menos al final.</returns>
        ''' <remarks>Nunca lanza excepciones. Si la cadena es más corta que el número de caracteres que se desea recortar, se devuelve cadena vacía.</remarks>
        ''' <example>Si "aString" vale "patata" y "longitud" vale "2", el resultado es "pata".</example>
        <Extension()>
        Public Function RecortarPorElFinal(ByVal aString As String, ByVal longitud As Integer) As String
            Dim resultado As String = ""
            If aString IsNot Nothing AndAlso aString.Length > longitud Then
                resultado = aString.Substring(0, aString.Length - longitud)
            End If
            Return resultado
        End Function
        <Extension()>
        Public Function ToMySql(d As Date) As String
            Return d.ToString("yyyy-MM-dd HH:mm:ss")
        End Function
        <Extension()>
        Public Function ConvierteDeWindowsARoman8(ByVal CadenaAconvertir As String) As String
            Return ConvierteStrings(CadenaAconvertir, codificacion.Caracteres.JuegoCaracteres.WINDOWS, codificacion.Caracteres.JuegoCaracteres.ROMAN8)
        End Function
        <Extension()>
        Public Function ConvierteDeWindowsARoman8SinAcentos(ByVal CadenaAconvertir As String) As String
            Return ConvierteStrings(CadenaAconvertir, codificacion.Caracteres.JuegoCaracteres.WINDOWS, codificacion.Caracteres.JuegoCaracteres.ROMAN8_SIN_ACENTOS)
        End Function
        <Extension()>
        Public Function ConvierteDeRoman8AWindows(ByVal CadenaAconvertir As String) As String
            Return ConvierteStrings(CadenaAconvertir, codificacion.Caracteres.JuegoCaracteres.ROMAN8, codificacion.Caracteres.JuegoCaracteres.WINDOWS)
        End Function
        <Extension()>
        Public Function ConvierteAAlfanumerico(ByVal StringOrigen As String, Optional cOrigen As String = "ÁÉÍÓÚÜáéíóúü", Optional cDestino As String = "AEIOUUaeiouu", Optional cPermitidos As String = "ABCDEFGHIJKLMNÑOPQRSTUVWXYZabcdefghijklmnñopqrstuvwxyz0123456789,.") As String
            Try
                Dim iNumChar As Integer, i
                iNumChar = StringOrigen.Length - 1
                Dim idx As Integer
                Dim sDestino As String = ""
                For i = 0 To iNumChar
                    'If cPermitidos.Contains(StringOrigen.Substring(i, 1)) Then
                    '    sDestino &= StringOrigen.Substring(i, 1)
                    'Else
                    '    If cOrigen.Contains(StringOrigen.Substring(i, 1)) Then
                    '        idx = cOrigen.IndexOf(StringOrigen.Substring(i, 1))
                    '        sDestino &= cDestino.Substring(idx, 1)
                    '    Else
                    '        sDestino &= " "
                    '    End If
                    'End If
                    If cOrigen.Contains(StringOrigen.Substring(i, 1)) Then
                        idx = cOrigen.IndexOf(StringOrigen.Substring(i, 1))
                        sDestino &= cDestino.Substring(idx, 1)
                    Else
                        If cPermitidos.Contains(StringOrigen.Substring(i, 1)) Then
                            sDestino &= StringOrigen.Substring(i, 1)
                        Else
                            sDestino &= " "
                        End If
                    End If
                Next
                Return sDestino
            Catch ex As Exception
                Throw New Exception(ex.Message)
            End Try
        End Function

        Public Function ConvierteStrings(ByVal StringOrigen As String, ByVal jcOrigen As codificacion.Caracteres.JuegoCaracteres, ByVal jcDestino As codificacion.Caracteres.JuegoCaracteres) As String
            Try
                Dim iNumChar As Integer, i, pos As Integer
                Dim cAux(), cOrigen(), cDestino() As Char
                cOrigen = codificacion.Caracteres.juegos(jcOrigen)
                cDestino = codificacion.Caracteres.juegos(jcDestino)
                iNumChar = cOrigen.Length
                cAux = StringOrigen
                For i = 0 To iNumChar - 1
                    pos = 0
                    Do
                        pos = InStr(pos + 1, StringOrigen, cOrigen(i), CompareMethod.Binary)
                        If pos > 0 Then
                            cAux(pos - 1) = cDestino(i)
                        End If
                    Loop Until pos = 0
                Next
                ConvierteStrings = cAux
            Catch ex As Exception
                Throw New Exception(ex.Message)
            End Try
        End Function
        <Extension()>
        Public Function FechaHoraStringADateTime(Fecha As String, Optional NuloSiInvalido As Boolean = True) As DateTime?
            Try
                If Fecha = "0" OrElse Fecha = "" Then
                    Return Nothing
                Else


                    If Fecha.Length > 16 AndAlso Fecha.Substring(11, 1) = "/" Then
                        Dim f As Date = FechaStringADate(Fecha.Substring(0, 11), True)
                        Dim sHora = Fecha.Substring(12).Split(":")
                        Dim Hora As Integer = CInt(sHora(0))
                        Dim Minutos As Integer = CInt(sHora(1))
                        Dim Segundos As Integer = 0
                        If sHora.Length > 2 Then
                            Segundos = CInt(sHora(2))
                        End If
                        Return New DateTime(f.Year, f.Month, f.Day, Hora, Minutos, Segundos)
                    Else
                        If Fecha.Length = 16 AndAlso Fecha.Substring(10, 1) = "T" Then ' yyyy-MM-ddTHH:mm
                            Return New Date(CInt(Fecha.Substring(0, 4)), CInt(Fecha.Substring(5, 2)), CInt(Fecha.Substring(8, 2)), CInt(Fecha.Substring(11, 2)), CInt(Fecha.Substring(14, 2)), 0)
                        Else
                            If Fecha.Contains(".") Then
                                Dim HoraMinutos = CInt(Fecha.Split(".")(1).Acortar(4).PadRight(4, "0"))
                                Dim Minuto = (HoraMinutos Mod 100) / 100 * 60
                                Dim Hora = Math.Truncate(HoraMinutos / 100)
                                Return New Date(CInt(Fecha.Substring(0, 4)), CInt(Fecha.Substring(4, 2)), CInt(Fecha.Substring(6, 2)), Hora, Minuto, 0)
                            Else
                                If Fecha.Length = 19 Then
                                    Return Date.Parse(Fecha)
                                ElseIf Fecha.Length = 14 Then
                                    Return New Date(CInt(Fecha.Substring(0, 4)), CInt(Fecha.Substring(4, 2)), CInt(Fecha.Substring(6, 2)), CInt(Fecha.Substring(8, 2)), CInt(Fecha.Substring(10, 2)), CInt(Fecha.Substring(12, 2)))
                                ElseIf Fecha.Length = 12 Then
                                    Return New Date(CInt(Fecha.Substring(0, 4)), CInt(Fecha.Substring(4, 2)), CInt(Fecha.Substring(6, 2)), CInt(Fecha.Substring(8, 2)), CInt(Fecha.Substring(10, 2)), 0)
                                ElseIf Fecha.Length = 11 Then
                                    Return FechaStringADate(Fecha, True)
                                Else
                                    Return New Date(CInt(Fecha.Substring(0, 4)), CInt(Fecha.Substring(4, 2)), CInt(Fecha.Substring(6, 2)), 0, 0, 0)
                                End If
                            End If
                        End If
                    End If
                End If
            Catch ex As Exception
                If NuloSiInvalido Then
                    Return Nothing
                Else
                    Throw New Exception(ex.Message, ex)
                End If
            End Try
        End Function

        <Extension()>
        Public Function FechaStringADate(Fecha As String, Optional NuloSiInvalido As Boolean = True) As Date?
            Try
                Fecha = Fecha.Trim
                If Fecha = "0" Or Fecha = "" Then
                    Return Nothing
                Else
                    Dim cSeparador As String = ""
                    If Fecha.Contains("de") Then
                        Fecha = Fecha.Replace(" de ", "-")
                    End If
                    If Fecha.Contains("-") Then cSeparador = "-"
                    If Fecha.Contains("/") Then cSeparador = "/"
                    If Fecha.Contains(".") Then
                        If Fecha.Split(".")(0).Length >= 8 Then
                            Fecha = Fecha.Split(".")(0)
                        Else
                            If cSeparador = "" Then cSeparador = "."
                        End If
                    End If
                    Dim iMes As Integer = 0
                    If Fecha.ToLower.Contains("ene") Or Fecha.ToLower.Contains("enero") Then iMes = 1
                    If Fecha.ToLower.Contains("feb") Or Fecha.ToLower.Contains("febrero") Then iMes = 2
                    If Fecha.ToLower.Contains("mar") Or Fecha.ToLower.Contains("marzo") Then iMes = 3
                    If Fecha.ToLower.Contains("abr") Or Fecha.ToLower.Contains("abril") Then iMes = 4
                    If Fecha.ToLower.Contains("may") Or Fecha.ToLower.Contains("mayo") Then iMes = 5
                    If Fecha.ToLower.Contains("jun") Or Fecha.ToLower.Contains("junio") Then iMes = 6
                    If Fecha.ToLower.Contains("jul") Or Fecha.ToLower.Contains("julio") Then iMes = 7
                    If Fecha.ToLower.Contains("ago") Or Fecha.ToLower.Contains("agosto") Then iMes = 8
                    If Fecha.ToLower.Contains("sep") Or Fecha.ToLower.Contains("septiembre") Then iMes = 9
                    If Fecha.ToLower.Contains("oct") Or Fecha.ToLower.Contains("octubre") Then iMes = 10
                    If Fecha.ToLower.Contains("nov") Or Fecha.ToLower.Contains("noviembre") Then iMes = 11
                    If Fecha.ToLower.Contains("dic") Or Fecha.ToLower.Contains("diciembre") Then iMes = 12
                    If cSeparador = "" Then
                        If Fecha.Length = 6 Then Fecha = "19" & Fecha
                        Return New Date(Integer.Parse(Fecha.Substring(0, 4)), Integer.Parse(Fecha.Substring(4, 2)), Integer.Parse(Fecha.Substring(6, 2)))
                        'Throw New Exception("formato de fecha no soportado")
                    Else
                        Dim mFecha() As String
                        mFecha = Fecha.Split(cSeparador)
                        If mFecha(0).Length >= 4 Then
                            Dim año As Integer = Integer.Parse(mFecha(0).Replace(".", "").Acortar(4))
                            If año < 100 Then año += 2000
                            If iMes > 0 Then
                                Return New Date(año, iMes, Integer.Parse(mFecha(2)))
                            Else
                                Return New Date(año, Integer.Parse(mFecha(1).ToString), Integer.Parse(mFecha(2)))
                            End If
                        Else
                            Dim año As Integer = Integer.Parse(mFecha(2).Replace(".", "").Acortar(4))
                            If año < 100 Then año += 2000
                            If iMes > 0 Then
                                Return New Date(año, iMes, Integer.Parse(mFecha(0)))
                            Else
                                Return New Date(año, Integer.Parse(mFecha(1).ToString), Integer.Parse(mFecha(0)))
                            End If
                        End If
                    End If
                End If
            Catch ex As Exception
                If NuloSiInvalido Then
                    Return Nothing
                Else
                    Throw New Exception(ex.Message, ex)
                End If
            End Try
        End Function
        <Extension()>
        Public Function FechaHoraAstring(FechaHora As DateTime) As String
            Return FechaHora.Year.ToString & FechaHora.Month.ToString.PadLeft(2, "0") & FechaHora.Day.ToString.PadLeft(2, "0") & FechaHora.Hour.ToString.PadLeft(2, "0") & FechaHora.Minute.ToString.PadLeft(2, "0") & FechaHora.Second.ToString.PadLeft(2, "0")
        End Function
        ''' <summary>
        ''' Compute LevenshteinDistance.
        ''' </summary>
        <Extension()>
        Public Function LevenshteinDistance(ByVal s As String, ByVal t As String) As Integer
            Dim n As Integer = s.Length
            Dim m As Integer = t.Length
            Dim d(n + 1, m + 1) As Integer

            If n = 0 Then
                Return m
            End If

            If m = 0 Then
                Return n
            End If

            Dim i As Integer
            Dim j As Integer

            For i = 0 To n
                d(i, 0) = i
            Next

            For j = 0 To m
                d(0, j) = j
            Next

            For i = 1 To n
                For j = 1 To m

                    Dim cost As Integer
                    If t(j - 1) = s(i - 1) Then
                        cost = 0
                    Else
                        cost = 1
                    End If

                    d(i, j) = Math.Min(Math.Min(d(i - 1, j) + 1, d(i, j - 1) + 1),
                         d(i - 1, j - 1) + cost)
                Next
            Next

            Return d(n, m)
        End Function
        <Extension()>
        Public Function EliminarComillasTipograficas(s As String) As String
            If Not String.IsNullOrEmpty(s) Then
                Return s.Replace("‘"c, "'"c).Replace("’"c, "'"c).Replace(ChrW(&H201C), """"c).Replace(ChrW(&H201D), """"c)
            Else
                Return s
            End If
        End Function

        <Extension()>
        Public Function PrimeraLetraMayusculas(s As String) As String
            If s <> "" Then
                Return s.First().ToString().ToUpper() + [String].Join("", s.Skip(1)).ToLower
            Else
                Return ""
            End If
        End Function

        <Extension()>
        Public Function PrimeraLetraFraseMayusculas(s As String) As String
            If s.Trim <> "" Then
                Dim spalabras = s.Split(" ")
                Dim sResultado As String = ""
                For Each p In spalabras
                    sResultado &= " " & p.PrimeraLetraMayusculas
                Next
                Return sResultado.Substring(1)
            Else
                Return ""
            End If
        End Function
        <Extension()>
        Public Function PrimeraLetraFraseMayusculasSinArticulos(s As String) As String
            If s.Trim <> "" Then
                Dim spalabras = s.Split(" ")
                Dim sResultado As String = ""
                For Each p In spalabras
                    sResultado &= " " & p.PrimeraLetraMayusculas
                Next
                sResultado = sResultado.Substring(1)
                sResultado = sResultado.Replace(" El ", " el ").Replace(" Y ", " y ").Replace(" Lo ", " lo ").Replace(" La ", " la ").Replace(" DeL ", " del ").Replace(" De ", " de ").Replace(" Los ", " los ").Replace(" Las ", " las ")
                Return sResultado
            Else
                Return ""
            End If
        End Function

        Public Function EliminaPalabrasComunes(palabras As List(Of String)) As List(Of String)
            Dim PalabrasAEliminar As String()
            PalabrasAEliminar = {"a", "ante", "bajo", "cabe", "con", "contra", "de", "desde", "durante", "en", "entre", "hacia", "hasta", "mediante", "para", "por", "segun", "sin", "so", "sobre", "tras", "versus", "", "via", "el", "la", "lo", "los", "las", "un", "una", "uno", "unos", "al", "del", "que", "ya"}
            Return palabras.Except(PalabrasAEliminar).ToList
        End Function

        '<Extension()>
        'Public Function ReemplazarAcentos(value As String) As String

        '    If (String.IsNullOrEmpty(value)) Then Return String.Empty

        '    Dim caracteresNoPermitidos As String = "áéíóúàèìòùÁÉÍÓÚÀÈÌÒÙäÄëËïÏöÖüÜ"

        '    ' NO ELIMINAR LOS CARACTERES REPETIDOS, Y RESPETAR EL ORDEN
        '    ' EN EL QUE SE ENCUENTRAN DEFINIDOS. Si se añaden más caracteres
        '    ' no permitidos, añadir en la misma posición su correspondiente
        '    ' carácter permmitido.
        '    '
        '    Dim caracteresPermitidos As String = "aeiouaeiouAEIOUAEIOUaAeEiIoOuU"

        '    Dim chars As Char() = caracteresNoPermitidos.ToCharArray()

        '    Dim buffer As New System.Text.StringBuilder(256)

        '    buffer.Append(value)

        '    For Each letra As Char In value
        '        ' NOTA: para utilizar el método Contains hay que
        '        ' importar el espacio de nombres System.Linq, lo que
        '        ' significa utilizar .NET 3.5 o superior.
        '        '
        '        If (chars.Contains(letra)) Then
        '            Dim index As Int32 = caracteresNoPermitidos.IndexOf(letra)
        '            buffer.Replace(letra, caracteresPermitidos(index))
        '        End If
        '    Next

        '    Return buffer.ToString()

        'End Function
        <Extension()>
        Public Function SoloLetrasYNumeros(cadena As String) As String
            Dim pattern As String = "[^a-zA-Z0-9ñÑ ]"
            Return Regex.Replace(cadena, pattern, String.Empty)

        End Function

        <Extension()>
        Public Function ReemplazarAcentos(value As String) As String
            Dim toReplace() As Char = "àèìòùÀÈÌÒÙ äëïöüÄËÏÖÜ âêîôûÂÊÎÔÛ áéíóúÁÉÍÓÚðÐýÝ ãõÃÕšŠžŽçÇåÅøØ".ToCharArray
            Dim replaceChars() As Char = "aeiouAEIOU aeiouAEIOU aeiouAEIOU aeiouAEIOUdDyY aoAOsSzZcCaAoO".ToCharArray
            For index As Integer = 0 To toReplace.GetUpperBound(0)
                value = value.Replace(toReplace(index), replaceChars(index))
            Next
            Return value
        End Function

        <Extension()>
        Public Function RemoveDiacritics(ByVal text As String) As String
            If text IsNot Nothing Then
                Dim normalizedString = text.Normalize(NormalizationForm.FormD)
                Dim stringBuilder = New StringBuilder(capacity:=normalizedString.Length)

                For i As Integer = 0 To normalizedString.Length - 1
                    Dim c As Char = normalizedString(i)
                    Dim unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c)

                    If unicodeCategory <> UnicodeCategory.NonSpacingMark Then
                        stringBuilder.Append(c)
                    End If
                Next

                Return stringBuilder.ToString().Normalize(NormalizationForm.FormC)
            Else
                Return ""
            End If
        End Function

    End Module
End Namespace
