Alejandro B. Martin - Blog de Asp.Net y MsSQL

Agosto 15, 2008

Eliminar cualquier conjunto de etiquetas Html (tags) de apertura y cierre

Necesitaba un código Regex que me eliminase todas las etiquetas <a href ..></a> (de apertura y cierre) de cualquier cadena de texto (string).

ANTES:
“mi web es <a href=”miweb.com”>www.miweb.com</a> veréis que chula, ver también <a href=’www.otraweb.com’ target=”_blank”>otraweb.com</ a>”

EL RESULTADO QUE SE QUIERE OBTENER:
“mi web es www.miweb.com veréis que chula, ver también otraweb.com”


Más de 1 hora buscando por internet y no he encontrado ningún código que me solucionase el problema.

He desarrollado una función, que además de solucionar el anterior problema, sirve para eliminar cualquier etiqueta HTML de las que tienen cierre.

El siguiente código es válido para eliminar etiquetas de apertura y cierre de cualquier cadena de caracteres, tales como; <a href, <div, <span, etc .., es decir, todas aquellas que tienen asociada una etiqueta de cierre; </a>, </div>, </span>, etc ..
Este código no es válido para eliminar etiquetas que no tengan asociada una de cierre; <br> (o <br/>), <hr>, etc .

La siguiente función eliminará todas las etiquetas tag html, incluyendo sus parámetros, pero mantendrá el texto contenido entre ellas.

Ideal para formatear código HTMl a texto plano.

    ''' <summary>
    ''' Elimina todas las etiquetas html (tags) de apertura y cierre. Mantiene (no elimina) el texto contenido entre ellas.
    ''' </summary>
    ''' <param name="str">La cadena de texto (string) sobre la cuál se quieren eliminar las etiquetas</param>
    ''' <param name="TagStart">Determinada etiqueta para la cual se quieran eliminar sus aperturas y cierres. 
    ''' Debe incluirse el char. de apertura seguido del nombre de la etiqueta</param>
    ''' ej: <a , <div , <span , etc .. 
    ''' <returns>Devuelve la cadena de texto del arg. "str", sin las etiquetas de apertura y cierre.</returns>
    ''' <remarks>Por Alejandro Barrada Martín</remarks>
    Public Function RemoveHtmlTagsStartEnd(ByVal str As String, ByVal TagStart As String) As String
        Dim result As String = Nothing
        Dim HtmlTagEnd As String = TagStart.Replace("<", "").Replace("< ", "")
        For i As Integer = 0 To str.Length - 1
            If Not i >= str.Length - 1 - TagStart.Length Then
                If str.Substring(i, TagStart.Length) = TagStart Then
                    For j As Integer = i To str.Length - 1
                        If Not j >= str.Length - 1 - 2 Then
                            If str.Substring(j, 2) = """>" _
                            Or str.Substring(j, 2) = "'>" Or str.Substring(j, 2) = " >" Then
                                i = j + 2
                                Exit For
                            End If
                        End If
                    Next
                    For j As Integer = i To str.Length - 1
                        If Not j >= str.Length - 1 - HtmlTagEnd.Length - 1 Then
                            If str.Substring(j, 2 + HtmlTagEnd.Length) = "</" & HtmlTagEnd Then
                                i = j + 2 + HtmlTagEnd.Length
                                Exit For
                            ElseIf str.Substring(j, 3 + HtmlTagEnd.Length) = "</ " & HtmlTagEnd _
                            Or str.Substring(j, 3 + HtmlTagEnd.Length) = "< /" & HtmlTagEnd Then
                                i = j + 3 + HtmlTagEnd.Length
                                Exit For
                            Else
                                result &= str.Substring(j, 1)
                            End If
                        End If
                    Next
                Else
                    result &= str.Substring(i, 1)
                End If
            Else
                result &= str.Substring(i, 1)
            End If
        Next
        Return result
    End Function

Ejemplo de llamada a dicha función:

                Dim textoHtml As String _
                = "mi web es <a href='miweb.com'>www.miweb.com</a> veréis que chula" _
                 & ", ver también <a href='www.otraweb.com' target='_blank'>otraweb.com</ a>"
                Dim textoSinEtiquetasAHref As String = RemoveHtmlTagsStartEnd(textoHtml, "<a")
                Response.Write(textoSinEtiquetasAHref)

Como resultado se tendrá:

mi web es www.miweb.com veréis que chula, ver también otraweb.com


Finalizo el post indicando que, si alguien conoce algún patrón ReGex para lo siguiente, que postee, y tras comprobarlo lo publicaré en este mismo post, para que sea de ayuda a otros programadores.
Patrones Pendientes de Publicación:

1) Cómo eliminar etiquetas de apertura y cierre para una determinada etiqueta, es decir, eliminar <a href y todos sus parametros> mantener el texto entre las apertura y cierre </a eliminar etiqueta cierre>, pero usando algún patrón de expresión regular

2) Cómo eliminar todas las etiquetas (apertura y cierre, y también sólo apertura) de una cadena.
Ideal para los que quieran convertir un código HTML a texto plano.

Return system.Text.RegularExpressions.Regex.Replace("CadenaStringALaQueQuitarTodasLasTags", "<(.|\n)*?>", "")

A COLABORAR !

Agosto 13, 2008

Convertir un DataTable (de x DataSet) a formato tabla HTML

Para todos aquellos que necesiten pasar a código HTML cualquier tabla DataTable de cualquier versión del .Net, les muestro un simple método que podéis utilizar para tal fin.

    ''' <summary>
    ''' Convierte un DataTable en una tabla HTML (table).
    ''' </summary>
    ''' <param name="SrcAsDataTable">Cualquier DataTable.</param>
    ''' <returns></returns>
    ''' <remarks>Devuelve una cadena String con el DataTable y su contenido convertido a código HTML.</remarks>
    Public Shared Function ConvertDataTableToHtml(ByVal SrcAsDataTable As Data.DataTable) As String
        If (SrcAsDataTable Is Nothing) Then Throw New System.ArgumentNullException("SrcAsDataTable")
        Dim SB As System.Text.StringBuilder = New System.Text.StringBuilder()
        'Table Tag.
        SB.Append("<table border='1px' cellpadding='5' cellspacing='0' ")
        SB.Append("style='border: solid 1px Silver; font-size: x-small;'>")
        'Headings Tag row.
        SB.Append("<tr align='left' valign='top'>")
        For Each myColumn As Data.DataColumn In SrcAsDataTable.Columns
            SB.Append("<td align='left' valign='top'>")
            SB.Append(myColumn.ColumnName)
            SB.Append("</td>")
        Next
        SB.Append("</tr>")
        'Data Tags rows.
        For Each myRow As Data.DataRow In SrcAsDataTable.Rows
            SB.Append("<tr align='left' valign='top'>")
            For Each myColumn As Data.DataColumn In SrcAsDataTable.Columns
                SB.Append("<td align='left' valign='top'>")
                SB.Append(myRow(myColumn.ColumnName).ToString())
                SB.Append("</td>")
            Next myColumn
            SB.Append("</tr>")
        Next
        SB.Append("</table>")
        Return SB.ToString()
    End Function

Abril 25, 2008

Propiedades dinámicas

Con el presente explico -para aquellos a los que les pueda ser útil-, cómo consultar y asignar valores de forma dinámica a las propiedades de cualquier objeto o control de servidor. Requiere el Framework .Net 2.0+ (o superior)

A mi me costó bastante encotrar información, y me ha resultado de mucha utilidad para el gran proyecto -fase 1/3 para 2/3- que llevo desarrollando desde el 2007 [Fase1: GoldByWebs]

Primero mostraré el contexto con algún ejemplo y luego descubro el código mínimo-necesario para tal fin (para no enrollarse y para que descubras lo básico; así luego cada cual con lo suyo ..).

Supongamos que tenemos un GridView -o cualquier otro control e incluso un objeto(object)-, para el que los valores que queremos asignar a sus propiedades no los sabemos en tiempo de diseño; bien los recojemos de una base de datos, o bien de un array, o de donde sea pero sin saber de antemano; ni los valores que vamos a darlas, ni las mismas propiedades a las que asignar dichos valores, ..
-

EJEMPLO PRACTICO:
Tenemos un aplicativo en el que queremos que cada usuario pueda personalizar determinadas propiedades de un control GridView; al que llamaremos UserGridView.

Dynamic properties - Propiedades dinámicas con .Net

Los usuarios acceden a un formulario donde se les pide que definan que valores quieren personalizar para determinadas propiedades de un GridView:

El usuario Pepito a definido que quiere personalizar dicho gridview con los siguientes valores:
Caption = “Pepito quiere así su gridview”, Width = “400px” y Backcolor = “Yelow”

Fulanita por ello define:
Caption = “GridView de Fulanita”, Width = “550px” , Backcolor = “Pink” y BorderStyle=”Dashed”.

Dichos datos son guardados -están almacenados pues- en la base de datos.


COMO PODEMOS HACER PARA QUE A LOS USUARIOS SE LES MUESTRE EL GRID COMO ELLOS QUERIAN. COMO PODEMOS ASIGNAR PROPIEDADES DE FORMA DINAMICA EN .NET

::TENIENDO Y TOMANDO COMO BASE::

-Que determinada consulta a la base de datos para determinado usuario a devuelto un List(of ListItem) con el par “NombreDePropiedad/ValorQueDefinióElUsuario” (.text/.value) [aunque también podría tratarse de un datatable, etc ..]

Lo que muchos hacen, -sólo si saben las propiedades que pueden definir los usuarios, o bien si implementan condicionales tipo If Not IsNothing- es programar algo así como:
-EJEMPLO NO DINÁMICO-

‘[Consulta a la DBA para rellenar este List con el Par NombrePropiedad/Valor (.text/.value)]
Dim ObjPropertiesListOfListItem As New List(Of ListItem)


‘ Según el gráfico, en este caso No Dinámico, sabemos que 0=Caption

UserGridView.Caption = ObjPropertiesListOfListItem(0).Value

UserGridView.Width = ObjPropertiesListOfListItem(1).Value

‘ ..

-
-EJEMPLO DINAMICO- IMPLEMENTANDO PROPIEDADES DINAMICAS EN .NET - REFLECTION

        '.. [Consulta a la DBA para rellenar este List con el Par NombrePropiedad/Valor (.text/.value)]
        Dim ObjPropertiesListOfListItem As New List(Of ListItem)
yyy
        'Creamos un ArrayList que se rellena con las propiedades que descubre la Function arrPropiedadesDeObjeto para el GridView
        Dim arrDePropiedadesDeMiUserGridView As ArrayList = arrPropiedadesDeObjeto(UserGridView)
        'Para tantas propiedades customizadas cómo se recojiesen de la dba (almacenadas en: ObjPropertiesListOfListItem)
        For x = 0 To ObjPropertiesListOfListItem.Count - 1
            'Comprobamos si el objeto (UserGridView) admite -tiene- x determinada propiedad; buscando si esta en el array
            If arrDePropiedadesDeMiUserGridView.Contains(ObjPropertiesListOfListItem(x).Text) Then
                'Si fuere el caso, llamamos a SetProperty para customizar el objeto con el valor de propiedad
                SetProperty(UserGridView, ObjPropertiesListOfListItem(x).Text, ObjPropertiesListOfListItem(x).Value)
            End If
        Next

Ahora el Function y el Sub, tan esperados !!

    ''' <summary>Devuelve un array que contiene las propiedades de determinado objeto.</summary>
    ''' <param name="objeto">Cualquier objeto; aunque normalmente suelen ser Controles de Servidor</param>
    Public Function arrPropiedadesDeObjeto(ByVal objeto As Object) As ArrayList
        Dim PropertyInfo As System.Reflection.PropertyInfo() = objeto.GetType.GetProperties() 'Me.GetType.GetProperties()
        Dim PropertyItem As System.Reflection.PropertyInfo
        Dim _arrAvolver As New ArrayList
        For Each PropertyItem In PropertyInfo : _arrAvolver.Add(PropertyItem.Name) : Next
        Return _arrAvolver
    End Function
    ''' <summary>Adjudica un valor a una propiedad de un determinado objeto</summary>
    ''' <param name="Objeto">El objeto al que -por reflection- pasar el PropertyValue</param>
    ''' <param name="PropertyName">El nombre de la propiedad</param>
    ''' <param name="PropertyValue">El valor que se la quiere adjudicar</param>
    Public Sub SetProperty(ByVal Objeto As Object, ByVal PropertyName As String, ByVal PropertyValue As String)
        Dim userType As Type = Me.GetType()
        Dim UserProp As System.Reflection.PropertyInfo = userType.GetProperty(PropertyName)
        UserProp.SetValue(Objeto, PropertyValue, Nothing)
    End Sub

Las ventajas que ofrece el uso del dinamismo, són enormes en lo que refiere a escalabilidad, aunque hay que anotar que el uso de “Reflection” siempre conlleva una demora de tiempo, es decir, que las páginas o forms tardarán algo más en cargarse, pero no mucho ..

Copyright 25 Abril 2008 © Alejandro Barrada Martin - Reservados todos los derechos salvo consentimiento del autor.
El autor cede los derechos de publicación del presente artículo siempre y cuando se mencione al mismo y a esta url-dirección web.

Marzo 23, 2008

VS2008 RTM - Could not load file or assembly System.Data.DataSetExtensions, Version=2.0.0.0

Realizo este post para dar solución a todos aquellos programadores .Net que tengan el problema citado en el titular -del presente - a la hora de usar Visual Studio 2008 RTM (vs2008 Final Release).

Desde finales del 2007 que ando involucrado en el desarrollo de varios proyectos usando VS2008 Beta2, la cuál caducaba el pasado 17 de Marzo (2008). Al igual que otros muchos, hemos tenido que actualizarnos con la nueva -y por el momento única disponible- versión Final Release (la que sale antes de la oficial) de Visual Studio 2008 “Visual Studio 2008 RTM”.

Al cargar proyectos desarrollados con VS2008 Beta o Beta 2 que utilizen el Framework 3 o el 3.5, nos encontramos el siguiente mensaje de error:

Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Could not load file or assembly ‘System.Data.DataSetExtensions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′ or one of its dependencies. El sistema no puede hallar el archivo especificado.

Visual Studio 2008 Configuration Error
En la constante-cambiante plataforma .Net, era previsible que pudiera suceder; al igual que ya sucedió recientemente con el SP2 windows server

No te preocupes, no le ha pasado nada a tu proyecto ni a tus archivos, todo te va a seguir funcionando igual que antes, simplemente tendrás que cambiar un trocito de texto de tu archivo Web.Config.

Como ves en la imagen de arriba, el texto que aparece señalado (azul) es el que deberás cambiar:

  • Mal: Version=2.0.0.0
  • Bien: Version =3.5.0.0

Tras efectuar el simple cambio, compila de nuevo el proyecto y vualá! ya puedes seguir con tu preciado work !

Explicación lógica del “defecto”


La razón es que algunos de los assemblies pre-release Fx 3.5 aún no tenían su versión puesta a 3.5 en la Beta2, por ello que la RTM da errores (al si tenerlos actualizados a 3.5) .Realizad el simple cambio arriba indicado y “en principio” todo os debería correr.

NOTA IMPORTANTE: Se están descubriendo otros fallos tales como la imposible alineación de texto (indent) , la tremenda lentitud que se sufre al editar algunas webs u archivos de mucho código, y otros cuantos bastantes etcéteras, recomiendo bajar el Hot Fix que ha publicado Microsoft (que desastre, .. no si encima !) LINK: https://connect.microsoft.com/VisualStudio/Downloads/DownloadDetails.aspx?DownloadID=10826

Ya como los de google, con sus eternas versiones Beta para que luego no les achaquen (gmail, etc ..) Patraña de poffesionales. JJ!

Copyright 27 Febrero 2008 © Alejandro Barrada Martin - Reservados todos los derechos salvo consentimiento del autor.
El autor cede los derechos de publicación del presente artículo siempre y cuando se mencione al mismo y a esta url-dirección web.

Febrero 27, 2008

Formatear cadenas de Texto/String como númericas con o sin decimales - Regex - Expresiones Regulares

En este post voy a explicar cómo convertir cualquier cadena de texto que contenga letras y números de cualquier índole y posibilidad, a formato numérico utilizando para ello las expresiones regulares (regex : regular expressions). Es decir, recoger números, números con decimales, con o sin puntos y/o comas de separación, así como cualquiera de las anteriores.

Escribo este post, pues me ha resultado bastante complicado dar con la solución (dar con la cadena regex) adecuada para convertir cadenas de texto (strings) a números con o sin decimales, con o sin delimitadores (millares, etc ..).


Hmnn no hace falta que te leas todo este tocho. en este post te abrevio y te doy posiblemente la solución regex que buscasBREVE INTRO - REGEX EN .NET - RECOGER CADENA CON SÓLO SUS NUMEROS

No te asustes por el libro !, en este post encontrarás la solución para recoger de cadenas string, números con todo tipo de formato.

Primero una breve intro. sobre cómo usar las regular expressions en .Net (para más información sobre dicho mundo, al final de página referencio algunos links interesantes para aprender).

Para poder usar expresiones reguares a la hora de recojer, buscar o sustituir cadenas string, .Net nos provee del objeto regex. Dicho objeto viene cargado por defecto salvo que estés utilizando un proyecto de librería de clases en cuyo caso deberás importar su espacio de nombre:

Imports System.Text.RegularExpressions

Bien pues, ahora explico cómo utilizar dicho objeto para nuestro cometido, que tal cual reza el titular de este post, trata de obtener cadenas numéricas.
Empezaremos con algo sencillo para acabar ir avanzando hasta acabar con algo más complejo (decimales y separadores).

APRENDIENDO A USAR EL OBJETO

regex regular expressions, expresiones regulares numéricas en .net

Tomemos como ejemplo las siguientes variables:

Dim CadenaDeTextoSinFormato_comoNumeroEntero As String = “Importe : 150 Euros”

Dim ResultadoQueQueremosObtener_comoNumeroEntero As String

  • Para encontrar (seleccionar) una cadena que cumpla con determinado criterio usamos:

Dim CriterioDeExpresionRegularQueDebemosAplicar As String

ResultadoQueQueremosObtener_comoNumeroEntero = Regex.Match(CadenaDeTextoSinFormato_comoNumeroEntero, CriterioDeExpresionRegularQueDebemosAplicar).Value

play.gif EJ.: RECOJER NUMEROS

Empezaremos con algo sencillo, tomando como ejemplo las variables anteriores, podemos usar cualquiera de las siguientes expresiones regulares para obtener el/los números de la cadena de texto “importe : 150 Euros”. Podemos usar:

  • [d]+
    • Donde + indica que obtendrá todos los caracteres que sigan. Puede ser [d](2) si sólo queremos coger 2 caracteres (numéricos)
  • [0-9]+
    • Donde 0-9 indica que los caracteres deben estar entre el 0 y el 9

Que bien, dirás, ..
Pues si pero no, jj,

RECOGER TODO TIPO DE NUMÉRICOS - DESDE SIMPLES A COMPLEJOS

Si tubiésemos diferentes números, en diferente formato, con o sin Decimales, etc., en fín algo más complicado ..

Supongamos que (como el aquí presente), estás recogiendo datos de los que su formato sea variable(dinámico) .

numeros de todo tipo ¿?

Imagina que estas desarrollando una aplicación que debe guardar datos con formato numérico (integer, decimal, money o lo que sea).
Pero que tu aplicativo sólo recibe cadenas de texto, las que además de poder contener números - lo que tu app. debe recoger (importes (precios u otras)) - dichas cadenas pueden contener:

  • Cadenas de texto con un integer (entero numérico)
    • “Importe : 150 euros” o bien “€150″ <— este último caso esta en formato inglés (el símbolo de la moneda va antes que su cantidad)
  • Números con decimal o decimales
    • “Kilogramos : 1.55 “, “150 euros”, ..
  • Números con separadores
    • “1,400,000 euros”, “150.30 Kb”, ..
  • Números con decimales y con separadores
  • “1.999,99 euros”, ..
  • Con formato a la inglesa (el punto por la coma y viceversa)
  • “1,999.54 euros”, “150 euros”, ..

Como veis, són muchos los casos que nos podemos encontrar, más aún si se trata de formatos diferentes según países (ver los 2ºs ejemplos).

En este post no voy a exponer todas las expresiones regulares que harían falta para recojer los valores anteriormente expuestos en cualquier combinación de los mismos pues el post sería larguíssimo.

Pero basta con deciros que

  • Por una parte expongo abajo varios enlaces; incluidos portales donde se pueden encontrar centenas de expresiones regex para til fin.
  • Pero y Más aún por otro, y el mejor de todos (tras búscar y buscar, probar y probar) ..
  • OS MUESTRO LA QUE POSIBLEMENTE SEA LA ÚNICA EXPRESION REGULAR QUE NECESITÉIS PARA OBTENER DATOS NUMÉRICOS, ESTÉN EN EL FORMATO QUE ESTÉN

b(?:d{1,3}(?(?=[,.])[,.](?:d{3}(?:[.,](?=d)|b)|(?:b|d{1,2}))|b))+

Vale que sea muy larga, pero con dicha regex conseguireis cualquier valor numérico que se encuentre en una cadena de caracteres, tal cuál estuviese excrito.
Así pues, con 1 misma expresión extraeremos siempre el contenido numérico esté en el formato que esté.

A los que se pregunten, ¿Porqué no puedo usar otra expresión regular más pequeña?, les respondo.
Si bien es cierto y correcto utilizar expresiones más sencillas, debo advertir, que si os cambian el formato de las cifras, vuestro regex fallará o no recogerá correctamente los datos.

play.gif RESUMEN

Si quereis capturar númericos de los que su formato y expresión pueda variar; con o sin decimales, con o sín separadores de millar y otros y, estén en el formato que estén (inglés, americano, Español, ..) entonces, así como si quereis despreocupación, utilizad dicha expresión, que repito s:

b(?:d{1,3}(?(?=[,.])[,.](?:d{3}(?:[.,](?=d)|b)|(?:b|d{1,2}))|b))+

Nota* Si en una misma cadena string existen varios números separados, es decir por ejemplo “unidades : 3 — importe x ud.: 5,5 — total: 16,5 euros” debéis separar antes (dividir) la cadena en 3 (o tantas partes como números que querais coger contenga)

_

_

_

Links relacionados

www.regular-expressions.info <– info con manuales

http://regexlib.com/DisplayPatterns.aspx?cattabindex=2&categoryid=3&p=2 <– Montón de expresiones con ejemplos de los resultados que se pueden conseguir, en concreto dicha url apunta a la página con exp. reg. para números, eso sí, la gran cadena mágica que aquí os he expuesto no creo que la encontrareis.

Espero que os sirva de ayuda y que os ahorre tiempo

Saludos

Copyright 27 Febrero 2008 © Alejandro Barrada Martin - Reservados todos los derechos salvo consentimiento del autor.
El autor cede los derechos de publicación del presente artículo siempre y cuando se mencione al mismo y a esta url-dirección web.

Entradas más antiguas »

Blog de WordPress.com.