Índice de la sección dedicada a .NET (en el Guille)

Utilidad para filtrar el código HTML generado por Word
Para que el Guille no se mosquee con las colaboraciones...

Publicado el 28/Feb/2005
Actualizado el 17/Ago/2006
Autor: Guillermo 'guille' Som


A ver si con esta utilidad os resulta más fácil enviar las colaboraciones que previamente habéis escrito con Word...

Nota del 17/Ago/2006:
El código y la forma de procesar los ficheros ha cambiado, así como las opciones del formulario principal y otras muchas cosas.

Por tanto la captura y el código mostrado es de la versión anterior.

Dejo los dos ZIP el anterior y el nuevo, en ambos está el código fuente y el ejecutable.
 

 

Esta utilidad lo que hace es una limpieza del código "basura que el Word añade a las páginas con formato HTML que crea a partir de un documento de tipo DOC.

Se que el formato es menos "bonito" que el que muestra el navegador antes de "filtrarlo", pero también es cierto que se reduce en más de la mitad, de forma que una página que con el formato de Word ocuparía 45 KB después de filtrarlo se queda en menos de 20 KB, aunque no siempre se reduce en esa misma proporción, pero como puedes comprobar es bastante significativa.

Otra de las cosas que proporciona esta utilidad es que se puede indicar el título, la descripción y las palabras clave, cosa que muchos olvidáis de especificar... para poder hacerlo más fácil, al menos en lo que al as palabras clave se refiere, he puesto una serie de botones de opciones y checks para que se pueda indicar fácilmente que lenguaje se ha usado, si usa ADO, ASP o APIs de Windows.

 

Novedades del 01/Mar/05:
Estas son las nuevas cosillas que le he añadido desde ayer:

1- Permite indicar los dos lenguajes principales de .NET: VB y C#, ya que algunos tenéis la buena costumbre de mostrar el código en los dos lenguajes... cualquier día lo pondré como "norma", je, je... ¡no te asustes! que es broma, pero si usas mi utilidad de convertir el código... lo puedes hacer casi en un "pis pás".

2- Puedes indicar el zip con el código de ejemplo, así no tendrás que escribir nada, además de que calcula el tamaño y lo incluye.

3- Al arrastrar el fichero comprueba si ya tiene el título, descripción, etc., y de ser así lo incluye en las cajas de textos correspondientes. Es que esto de las expresiones regulares, cuando funciona, es una maravilla, je, je, je.

4- Puedes arrastrar ficheros con formato DOC o RTF, en estos casos solamente extrae el texto, pero, lamentablemente no distingue entre texto normal y texto de código, y por supuesto las imágenes no sabe ni que existen... Pero es un paso... aunque lo mejor en estos casos es que primero conviertas el DOC en formato HTML usando Word y después lo filtras, (que esa era la función inicial de esta aplicación).

5- No se si le he añadido más cosas... pero lo que es seguro es que ahora funciona mejor que ayer... je, je... ¡Ah! ¡Sí!, ahora tiene en cuenta si es un artículo de .NET o VB6 y utiliza tanto el link para la página de colaboraciones adecuada, como la imagen del link superior y, por supuesto el path correcto para el fichero ZIP, (si es que lo has indicado).
 

En la siguiente imagen tienes una captura de la utilidad en plena ejecución:

 


La utilidad esperando el fichero a convertir

 

En el ZIP te dejo tanto el ejecutable como el código para que veas cómo lo he hecho o para que la puedas mejorar o adaptar a tus necesidades.
 

Como nota adicional, decirte que si quieres ver ejemplos de cómo usar expresiones regulares para quitar y cambiar texto, así como para tener ejemplos de cómo usar el StringBuilder y algunas cosillas más, te veas el código... por ahora solo está en VB, pero espero que dentro de unos días incluya el de C# (cuando compruebe que no haré nuevas modificaciones).

 

Nota:
Si no te interesa la utilidad, porque no vas a colaborar en este sitio, y no quieres bajártela, un poco más abajo tienes parte del código para VB .NET.

 

Espero que la utilices y, aunque no es perfecta, al menos con pocos cambios, puedes dejar la colaboración "más o menos" como pido en la página de colaboraciones.

Muchas gracias.

Nos vemos.
Guillermo

 

Los ZIP:

El zip con el ejecutable y el código para VB .NET: FiltrarHTMLparaElguille.zip 38.8 KB (versión del 16/Jun/2005)

El zip con el ejecutable y el código para VB .NET: FiltrarHTMLparaElguille_1.1.zip 52.6 KB (17/Ago/2006)

MD5 checksum: 0B83F6281B01B007C832D6EDEC4C592D

Nota:
En la nueva "versión" de la utilidad (v1.1.*) se utilizan una serie de ficheros con parte del código interno a usar, esos ficheros deben estar en el mismo directorio del ejecutable y se incluyen tanto en formato .txt como en un zip que los contiene. Todos esos ficheros están dentro del ZIP arriba indicado.


El código para Visual Basic .NET

Recuerda que este código es de la versión anterior al 17/Ago/2006.
Pulsa aquí si quieres ver el código de la clase para manejar los datos de configuración.

'------------------------------------------------------------------------------
' Filtrar las páginas HTML creadas con Word			     (27/Feb/05)
' para que se adapten al estilo de mi sitio
'
' Revisado el 28/Feb y 01/Mar/2005 con nuevas opciones y características
'
' ©Guillermo 'guille' Som, 2005
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On 

Imports System
Imports Microsoft.VisualBasic
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Windows.Forms
Imports System.Collections
Imports System.Xml
Imports System.Configuration

Public Class fFiltrarHTML
   Inherits System.Windows.Forms.Form
   '
   Private configXml As New XmlDocument
   Private ficConfig As String
   Private valores As IDictionary = Nothing
   Private seccionAnt As String = ""
   '
   Public Sub New()
      MyBase.New()

      'El Diseñador de Windows Forms requiere esta llamada.
      InitializeComponent()

      'Agregar cualquier inicialización después de la llamada a InitializeComponent()
      ficConfig = Application.ExecutablePath & ".config"
      '
      ' comprobar si exite el fichero de configuración
      If System.IO.File.Exists(ficConfig) = False Then
         Dim sXml As New System.Text.StringBuilder
         '
         ' crear la cadena a asignar al objeto XmlDocument
         sXml.Append("<configuration>")
         sXml.Append("  <appSettings>")
         sXml.Append("   <!--   La configuración de la aplicación de usuario y de la propiedad configurada van aquí.-->")
         sXml.Append("   <!--   Ejemplo: <add key=""settingName"" value=""settingValue""/> -->")
         sXml.Append("   <add key=""txtTitulo.Text"" value="""" />")
         sXml.Append("   <add key=""txtKeywords.Text"" value="".NET; VB;"" />")
         sXml.Append("   <add key=""txtDescripcion.Text"" value="""" />")
         sXml.Append("   <add key=""optNET.Checked"" value=""False"" />")
         sXml.Append("   <add key=""optVBNET.Checked"" value=""False"" />")
         sXml.Append("   <add key=""optVBNET.Enabled"" value=""True"" />")
         sXml.Append("   <add key=""optCS.Checked"" value=""False"" />")
         sXml.Append("   <add key=""optCS.Enabled"" value=""True"" />")
         sXml.Append("   <add key=""optVB6.Checked"" value=""False"" />")
         sXml.Append("   <add key=""chkASP.Checked"" value=""False"" />")
         sXml.Append("   <add key=""chkADO.Checked"" value=""False"" />")
         sXml.Append("   <add key=""chkAPI32.Checked"" value=""False"" />")
         sXml.Append("   <add key=""txtZip.Text"" value="""" />")
         '
         sXml.Append("   <add key=""Form1.Left"" value=""0"" />")
         sXml.Append("   <add key=""Form1.Top"" value=""0"" />")
         sXml.Append("  </appSettings>")
         sXml.Append("</configuration>")
         '
         ' asignamos la cadena al objeto
         configXml.LoadXml(sXml.ToString)
         '
         ' Guardamos el contenido de configXml y creamos el fichero
         configXml.Save(ficConfig)
      Else
         ' solo es necesario leerlo si no lo hemos creado
         configXml.Load(ficConfig)
      End If
      '
      Me.txtTitulo.Text = cfgGetValue("configuration/appSettings", "txtTitulo.Text", "")
      Me.txtKeywords.Text = cfgGetValue("configuration/appSettings", "txtKeywords.Text", "")
      Me.txtDescripcion.Text = cfgGetValue("configuration/appSettings", "txtDescripcion.Text", "")
      Me.txtZip.Text = cfgGetValue("configuration/appSettings", "txtZip.Text", "")
      '
      Me.Left = CInt(cfgGetValue("configuration/appSettings", "Form1.Left", Me.Left.ToString))
      Me.Top = CInt(cfgGetValue("configuration/appSettings", "Form1.Top", Me.Top.ToString))
   End Sub
   '
   ' El punto de entrada de la aplicación
   <STAThread()> _
   Public Shared Sub Main(ByVal args() As String)
      System.Windows.Forms.Application.EnableVisualStyles()
      System.Windows.Forms.Application.Run(New fFiltrarHTML)
   End Sub
   '

#Region " Código generado por el Diseñador de Windows Forms "

   ' El código del diseñador de Windows.Forms

#End Region

   '
   Private Sub btnFiltrar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFiltrar.Click
      ' Filtrar página HTML
      Dim sbHead As New StringBuilder
      Dim sbBody As New StringBuilder
      Dim sbPie As New StringBuilder
      Dim sbPBox As New StringBuilder
      Dim sbZIP As New StringBuilder
      Dim sb As New StringBuilder
      Dim sTexto As String
      Dim re As Regex
      Dim m As Match
      Dim avisos As New System.Collections.ArrayList
      Dim i, j, k As Integer
      '
      lblInfo.Text = "Procesando el fichero... paciencia..."
      lblInfo.Refresh()
      Me.Cursor = Cursors.WaitCursor
      '
      ' Quitar:
      '   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
      '   Todo el Head y dejarlo al formato adecuado
      '      Copiar las secciones keywords, description, seccion y title
      '   <span...></span>
      '   <o:p></o:p>
      '   <style>...</style>
      ' Cambiar:
      '   <p...>  por <p><font face='Verdana' size='2'>
      '   </p>   por </font></p>
      '      Estos dos casos, si después de <p> no hay un <font...>
      '   <body...> y poner <body background="../../imagenes/cuadriculaGris30.gif" bgcolor="#FFFFFF" link="#0000FF" vlink="#0000FF" alink="#FF0000">
      ' Con esto ya se queda medio aceptable
      '
      avisos.Clear()
      '
      '
      re = New Regex("<!DOCTYPE\s*[^>]*\s*>", RegexOptions.IgnoreCase)
      sTexto = re.Replace(txtFic.Text, "")
      ' guardar los <meta keywords, description y seccion
      re = New Regex("<meta name\s*=\s*""description""\s*content\s*=\s*[^>]*\s*>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Singleline)
      m = re.Match(sTexto)
      If m.Success Then
         sb.AppendFormat("{0}{1}", m.Value, vbCrLf)
      Else
         If txtDescripcion.Text = "" Then
            sb.AppendFormat("<meta name=""description"" content="""">{0}", vbCrLf)
            avisos.Add("Debes indicar la descripción (ver <meta name =description)")
         Else
            sb.AppendFormat("<meta name=""description"" content=""{1}"">{0}", vbCrLf, txtDescripcion.Text)
         End If
      End If
      re = New Regex("<meta name\s*=\s*""keywords""\s*content\s*=\s*[^>]*\s*>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Singleline)
      m = re.Match(sTexto)
      If m.Success Then
         sb.AppendFormat("{0}{1}", m.Value, vbCrLf)
      Else
         If txtKeywords.Text = "" Then
            If Me.optVB6.Checked Then
               sb.AppendFormat("<meta name=""keywords"" content=""VB; VB6"">{0}", vbCrLf)
            Else
               If Me.optVBNET.Checked Then
                  sb.AppendFormat("<meta name=""keywords"" content="".NET; VB.NET"">{0}", vbCrLf)
               End If
               If Me.optCS.Checked Then
                  sb.AppendFormat("<meta name=""keywords"" content="".NET; C#"">{0}", vbCrLf)
               End If
            End If
            avisos.Add("Debes indicar las palabras claves que realmente indican las tecnologías usadas.")
         Else
            sb.AppendFormat("<meta name=""keywords"" content=""{1}"">{0}", vbCrLf, txtKeywords.Text)
         End If
      End If
      re = New Regex("(<title>.+)(</title>)", RegexOptions.IgnoreCase Or RegexOptions.Compiled)
      m = re.Match(sTexto)
      If m.Success Then
         If m.Value.ToLower().StartsWith("colabora") Then
            sb.AppendFormat("{0}{1}", m.Value, vbCrLf)
         ElseIf txtTitulo.Text <> "" Then
            sb.AppendFormat("<title>{1}</title>{0}", vbCrLf, txtTitulo.Text)
         End If
      Else
         If txtTitulo.Text = "" Then
            If Me.optNET.Checked Then
               sb.AppendFormat("<title>Colabora.NET: </title>{0}", vbCrLf)
            Else
               sb.AppendFormat("<title>Colabora: </title>{0}", vbCrLf)
            End If
            avisos.Add("Debes indicar el título de la colaboración, buscar <title> y escríbelo después de 'Colabora.NET: '")
         Else
            sb.AppendFormat("<title>{1}</title>{0}", vbCrLf, txtTitulo.Text)
         End If
      End If
      '
      ' quitar todo lo que haya entre <head> y </head>
      re = New Regex("<head>([^\b]*)</head>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "")
      '
      ' buscar los <span...> que contengan color
      '   realmente encuentra hasta </span>
      ' este realmente llega hasta otros span: <span([^>]*)color:(.*)?> 
      re = New Regex("<span([^>]*)color:(.*)?</span>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      Dim sColor As String
      Dim i1, j1, k1 As Integer
      Dim sbColor As New StringBuilder(sTexto)
      Dim sepColor As Char() = {"'"c, ChrW(34), ";"c, ">"c}
      Dim ms As MatchCollection = re.Matches(sbColor.ToString)
      '
      k = "color:".Length
      k1 = "</span>".Length
      For Each m In ms
         i = m.Value.ToLower.IndexOf("color:")
         If i > -1 Then
            ' buscar hasta el próximo caracter que no sea una letra
            j = m.Value.IndexOfAny(sepColor, i)
            If j = -1 Then
               j = m.Value.Length
            End If
            sColor = m.Value.Substring(i + k, j - (i + k))
            i1 = m.Index
            '
            j1 = m.Value.IndexOf(">")
            sColor = "<font color=" & sColor & ">" & m.Value.Substring(j1 + 1)
            sColor = sColor.ToLower.Replace("</span>", "</font>")
            ' hay que rellenar la cadena resultante para
            ' que tenga los mismos caracteres que m.Value,
            ' sino, el StringBuilder no tendrá las mismas posiciones que
            ' el valor devuelto por cada m.Index
            sbColor.Replace(m.Value, rellenar(sColor, m.Value.Length), i1, m.Value.Length)
         End If
         Application.DoEvents()
      Next
      sTexto = sbColor.ToString
      ' quitar los <span...>
      re = New Regex("<span([^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "")
      ' quitar los </span>
      re = New Regex("</span>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "")
      ' quitar los <o:p> y </o:p>
      re = New Regex("</?o:p>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "")
      ' quitar lo que haya entre <style> y </style> (siempre que dentro no haya >...
      re = New Regex("<style>([^>]*)</style>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "")
      ' quitar el <html... >
      re = New Regex("<html([^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "")
      ' quitar el <body... >
      re = New Regex("<body([^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "")
      ' cambiar los <b ...> por <b>
      re = New Regex("<b\s([^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "<b>")
      ' Cambiar los <p...> por <p>
      re = New Regex("<p([^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "<p>")
      ' Cambiar los <blockquote...> por <blockquote>
      re = New Regex("<blockquote([^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "<blockquote>")
      ' Cambiar los <Div...> por <blockquote>
      re = New Regex("<div([^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "<blockquote>")
      ' cambiar los </div> por </blockquote>
      re = New Regex("</div>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Multiline)
      sTexto = re.Replace(sTexto, "</blockquote>")
      '
      '(<!--\[if gte mso 9\]>) (<!\[endif\]-->) / <!--[if gte mso 10]>
      k = "<![endif]-->".Length
      Do
         i = sTexto.ToLower().IndexOf("<!--[if gte mso 9]>")
         If i = -1 Then Exit Do
         j = sTexto.ToLower().IndexOf("<![endif]-->", i + 1)
         If j = -1 Then Exit Do
         sTexto = sTexto.Substring(0, i - 1) & sTexto.Substring(j + k)
      Loop
      Do
         i = sTexto.ToLower().IndexOf("<!--[if gte mso 10]>")
         If i = -1 Then Exit Do
         j = sTexto.ToLower().IndexOf("<![endif]-->", i + 1)
         If j = -1 Then Exit Do
         sTexto = sTexto.Substring(0, i - 1) & sTexto.Substring(j + k)
      Loop
      '
      ' quitar desde </body> hasta el final
      i = sTexto.ToLower().IndexOf("</body>")
      If i > -1 Then
         sTexto = sTexto.Substring(0, i - 1)
      End If
      '
      sbHead.AppendFormat("<html>{0}", vbCrLf)
      sbHead.AppendFormat("<head>{0}", vbCrLf)
      sbHead.AppendFormat("<meta http-equiv=""Window-target"" content=""_top"">{0}", vbCrLf)
      sbHead.AppendFormat("<meta http-equiv=""Content-Type"" content=""text/html; charset=windows-1252"">{0}", vbCrLf)
      sbHead.AppendFormat("<meta name=""MS.LOCALE"" content=""es"">{0}", vbCrLf)
      If Me.optNET.Checked Then
         sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DocSet:NETFramework"" />{0}", vbCrLf)
         If Me.optCS.Checked Then
            sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DevLang:CSharp"" />{0}", vbCrLf)
            sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DocSet:C#"" />{0}", vbCrLf)
         Else
            sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DevLang:VB"" />{0}", vbCrLf)
            sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DocSet:Visual Basic"" />{0}", vbCrLf)
         End If
      Else
         sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DevLang:VB"" />{0}", vbCrLf)
         sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DocSet:Visual Basic"" />{0}", vbCrLf)
      End If
      '
      If Me.chkASP.Checked Then
         sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DevLang:ASP"" />{0}", vbCrLf)
      End If
      If Me.chkADO.Checked Then
         sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DocSet:ADO"" />{0}", vbCrLf)
      End If
      If Me.chkAPI32.Checked Then
         sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DocSet:Win32 API"" />{0}", vbCrLf)
      End If
      sbHead.AppendFormat("<meta name=""MSHAttr"" content=""DocSet:XML"" />{0}", vbCrLf)
      '
      sbHead.Append(sb.ToString)
      sbHead.AppendFormat("<meta name=""seccion"" content=""Colabora.NET"">{0}", vbCrLf)
      sbHead.AppendFormat("</head>{0}", vbCrLf)
      '
      sbBody.AppendFormat("<body background=""../../imagenes/cuadriculaGris30.gif"" bgcolor=""#FFFFFF"" link=""#0000FF"" vlink=""#0000FF"" alink=""#FF0000"">{0}", vbCrLf)
      sbBody.Append(vbCrLf)
      sbBody.AppendFormat("<script language=""JavaScript"">{0}", vbCrLf)
      sbBody.AppendFormat("var gsPath = ""../../""{0}", vbCrLf)
      sbBody.AppendFormat("function IrADeLista(){{{0}", vbCrLf)
      sbBody.AppendFormat("   var s1 = gsBanner.D1.selectedIndex;{0}", vbCrLf)
      sbBody.AppendFormat("   var s2 = gsBanner.D1.options[s1].value;{0}", vbCrLf)
      sbBody.AppendFormat("   if( s2 != ""Selecciona"" ){0}", vbCrLf)
      sbBody.AppendFormat("      window.location = gsPath + s2;{0}", vbCrLf)
      sbBody.AppendFormat("}}{0}", vbCrLf)
      sbBody.AppendFormat("</script>{0}", vbCrLf)
      sbBody.AppendFormat("<script language=""JavaScript"" src=""../../elGuille.js""></script>{0}", vbCrLf)
      sbBody.AppendFormat("<hr noshade size=""3"">{0}", vbCrLf)
      '
      If Me.optNET.Checked Then
         sbBody.AppendFormat("<p align=""right""><font face=""Verdana""><a href=""../colaboraNET.htm"">{0}", vbCrLf)
         sbBody.AppendFormat("<img src=""../../imagenes/colabora_guillepuntonet.jpg"" align=""baseline"" border=""0"" width=""500"" height=""30""></a></font></p>{0}", vbCrLf)
      Else
         sbBody.AppendFormat("<p align=""right""><font face=""Verdana""><a href=""../colabora.htm"">{0}", vbCrLf)
         sbBody.AppendFormat("<img src=""../../imagenes/colabora_guille.jpg"" align=""baseline"" border=""0"" width=""500"" height=""30""></a></font></p>{0}", vbCrLf)
      End If
      '
      sbBody.Append(vbCrLf)
      '
      If sTexto.ToLower().IndexOf("tablePanorama") = -1 Then
         sbPBox.AppendFormat("<table border=""0"" cellpadding=""0"" style=""border-collapse: collapse"" width=""100%"" id=""tablePanorama"">{0}", vbCrLf)
         sbPBox.AppendFormat("<tr><td align=""left"" width=""80%"" valign=""top"">{0}", vbCrLf)
         sbPBox.AppendFormat("{0}", vbCrLf)
         sbPBox.AppendFormat("<p><font face=""Verdana""><strong><font size=""7"">[Título]</font><font size=""5""><br>{0}", vbCrLf)
         sbPBox.AppendFormat("[Subtítulo] </font>{0}", vbCrLf)
         sbPBox.AppendFormat("</font></strong></font></p>{0}", vbCrLf)
         sbPBox.AppendFormat("{0}", vbCrLf)
         sbPBox.AppendFormat("<p><font size=""2"" face=""Verdana""><strong>[Fecha:]<br>{0}", vbCrLf)
         sbPBox.AppendFormat("[Autor:]</strong></font></p>{0}", vbCrLf)
         sbPBox.AppendFormat("{0}", vbCrLf)
         sbPBox.AppendFormat("<p> </p>{0}", vbCrLf)
         sbPBox.AppendFormat("</td>{0}", vbCrLf)
         sbPBox.AppendFormat("<td align=""center"" width=""20%"" valign=""top"">{0}", vbCrLf)
         sbPBox.AppendFormat("<!--{0}", vbCrLf)
         sbPBox.AppendFormat("<iframe src=""http:"//www.panoramabox.com/Panoramabox.aspx?IdObj=NNNN""{0}", vbCrLf)
         sbPBox.AppendFormat("width=""180"" height=""240"" FRAMEBORDER=0 SCROLLING=NO></iframe>{0}", vbCrLf)
         sbPBox.AppendFormat("-->{0}", vbCrLf)
         sbPBox.AppendFormat("</td>{0}", vbCrLf)
         sbPBox.AppendFormat("</tr>{0}", vbCrLf)
         sbPBox.AppendFormat("</table>{0}", vbCrLf)
         sbPBox.AppendFormat("{0}", vbCrLf)
         sbPBox.AppendFormat("<hr noshade width=""90%"" size=""3"">{0}", vbCrLf)
      End If
      sbPBox.AppendFormat("<p><font face=""Verdana"" size=""2"">{0}", vbCrLf)
      '
      sbPie.AppendFormat("</font>{0}", vbCrLf)
      '
      sbPie.AppendFormat("<p> </p>{0}", vbCrLf)
      sbPie.AppendFormat("<hr noshade size=""3"">{0}", vbCrLf)
      sbPie.Append(vbCrLf)
      '
      ' Añadir el fichero a bajar                         (01/Mar/05)
      If Len(txtZip.Text) > 0 Then
         Dim fi As System.IO.FileInfo
         Try
            fi = New System.IO.FileInfo(txtZip.Text)
            sbPie.AppendFormat("<blockquote>{0}", vbCrLf)
            sbPie.AppendFormat("<p><font size=""2"" face=""Verdana""><b>{0}", vbCrLf)
            If optNET.Checked Then
               sbPie.AppendFormat("<a href=""http:"//downloads.elguille.info/BajarZip.aspx?seccion=/colabora/NET2005/&zip={1}"" target=""_blank""> {0}", vbCrLf, fi.Name)
            Else
               sbPie.AppendFormat("<a href=""http:"//downloads.elguille.info/BajarZip.aspx?seccion=/colabora/vb2005/&zip={1}"" target=""_blank""> {0}", vbCrLf, fi.Name)
            End If
            sbPie.AppendFormat("Fichero con el código de ejemplo:</a></b> {1} - {2} KB</font></p>{0}", vbCrLf, fi.Name, (fi.Length / 1024).ToString("0.00"))
            sbPie.AppendFormat("</blockquote>{0}", vbCrLf)
            sbPie.AppendFormat("<hr noshade size=""3"">{0}", vbCrLf)
            sbPie.Append(vbCrLf)
         Catch 'ex As Exception
         End Try
      End If
      '
      sbPie.AppendFormat("<p align=""center""><font size=""2"" face=""Verdana""><a href=""../../indice.asp"">{0}", vbCrLf)
      sbPie.AppendFormat("<img src=""../../imagenes/el_guille.jpg"" alt=""ir al índice"" border=""0"" width=""200"" height=""50""></a></font></p>{0}", vbCrLf)
      sbPie.AppendFormat("</body>{0}", vbCrLf)
      sbPie.AppendFormat("</html>{0}", vbCrLf)
      '
      sbHead.Append(sbBody.ToString)
      sbHead.Append(sbPBox.ToString)
      ' añadir el texto filtrado y quitar los dobles retornos de carro
      sbHead.Append(sTexto.Replace(vbCrLf & vbCrLf, vbCrLf))
      sbHead.Append(sbPie.ToString)
      '
      txtFic.Text = sbHead.ToString()
      txtFic.Refresh()
      '
      lblInfo.BackColor = System.Drawing.Color.FromKnownColor(Drawing.KnownColor.Control)
      lblInfo.ForeColor = System.Drawing.Color.FromKnownColor(Drawing.KnownColor.WindowText)
      lblInfo.Text = "Fichero procesado."
      lblInfo.Refresh()
      Me.Cursor = Cursors.Default
      '
      If avisos.Count > 0 Then
         sb = New StringBuilder
         For Each s As String In avisos
            sb.AppendFormat("{0}{1}", s, vbCrLf)
         Next
         MessageBox.Show(sb.ToString, "Cambios que debes hacer")
      End If
   End Sub
   '
   Private Function rellenar(ByVal s As String, ByVal n As Integer) As String
      Return (s & (New String(" "c, n))).Substring(0, n)
   End Function
   '
   Private Sub fFiltrarHTML_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles MyBase.DragDrop
      If e.Data.GetDataPresent("FileDrop") Then
         Dim sFic As String = CType(e.Data.GetData("FileDrop"), String())(0)
         '
         Dim zipExt As String = ".zip .rar"
         Dim htmExt As String = ".htm .html .asp .aspx .txt .doc .rtf .xml"
         Dim fi As New System.IO.FileInfo(sFic)
         If zipExt.IndexOf(fi.Extension) > -1 Then
            txtZip.Text = fi.FullName
         ElseIf htmExt.IndexOf(fi.Extension) > -1 Then
            ' si es .DOC o .RTF usar modo binario para abrirlo
            '
            Dim sr As New System.IO.StreamReader(sFic, System.Text.Encoding.Default)
            '
            ' si el formato es doc abrirlo en binario
            Select Case fi.Extension.ToLower
               Case ".doc"
                  Dim st As System.IO.Stream
                  st = sr.BaseStream
                  Dim b() As Byte
                  Dim offset As Integer
                  Dim fin As Integer
                  Dim sb As StringBuilder
                  ReDim b(CInt(st.Length - 1))
                  st.Read(b, 0, b.Length)
                  ' comprobar la posición x600, sino la xA00
                  offset = &H600
                  If b(offset) < 32 Then
                     offset = &HA00
                  End If
                  fin = Array.IndexOf(b, 0, offset)
                  If fin = -1 Then fin = b.Length
                  ' Convertir el array de bytes en una cadena
                  sb = New StringBuilder(Encoding.Default.GetChars(b, offset, fin - offset))
                  ' el último caracter a analizar será hasta el siguiente chr(0)
                  ' lo buscamos
                  fin = sb.ToString.IndexOf(ChrW(0))
                  ' quitamos todo lo que haya desde esa posición hasta el final
                  sb.Remove(fin, sb.Length - fin)
                  '
                  sb.Replace(vbCr, "<br>" & vbCrLf)
                  ' Quitar todos los caracteres no visibles
                  Dim sb2 As New StringBuilder("[")
                  For i As Integer = 1 To 9
                     sb2.AppendFormat("{0}", ChrW(i))
                  Next
                  For i As Integer = 11 To 12
                     sb2.AppendFormat("{0}", ChrW(i))
                  Next
                  For i As Integer = 14 To 31
                     sb2.AppendFormat("{0}", ChrW(i))
                  Next
                  sb2.Append("]")
                  Dim re As New Regex(sb2.ToString)
                  Me.txtFic.Text = re.Replace(sb.ToString, "")
                  '
               Case ".rtf"
                  ' usar un objeto RichTextBox para abrirlo
                  Dim rtb As New RichTextBox
                  rtb.LoadFile(fi.FullName)
                  Dim sb As New StringBuilder(rtb.Text)
                  sb.Replace(vbLf, "<br>" & vbCrLf)
                  Me.txtFic.Text = sb.ToString
                  rtb.Dispose()
                  '
               Case Else
                  Me.txtFic.Text = sr.ReadToEnd()
                  ' 
            End Select
            '
            sr.Close()
            ' 
            lblInfo.BackColor = System.Drawing.Color.Aqua
            lblInfo.ForeColor = System.Drawing.Color.Blue
            lblInfo.Text = "Comprueba o rellena las opciones antes de pulsar en FILTRAR"
            '
            ' comprobar el título, keywords, descripción y fichero zip
            comprobarTituloEtc()
         End If
         '
      End If
   End Sub
   ' 
   Private Sub fFiltrarHTML_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles MyBase.DragOver
      If e.Data.GetDataPresent("FileDrop") Then
         e.Effect = Windows.Forms.DragDropEffects.Copy
      End If
   End Sub
   '
   Private Sub fFiltrarHTML_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      lblInfo.Text = "Arrastra al textBox el fichero que quieres 'filtrar'"
      Dim sb As New StringBuilder
      sb.AppendFormat("Pega aquí el texto convertido con Word{0}{0}", vbCrLf)
      sb.AppendFormat("Después selecciona las opciones correspondientes de la derecha.{0}{0}", vbCrLf)
      sb.AppendFormat("Rellena (cambia o agrega) el contenido del título, descripción y keywords.{0}{0}", vbCrLf)
      sb.AppendFormat("Por último pulsa en el botón FILTRAR{0}", vbCrLf)
      sb.AppendFormat("y así tendrás un fichero 'limpio de polvo y paja' al que solo tendrás que{0}", vbCrLf)
      sb.AppendFormat("aplicarle los estilos para el texto normal y el código...{0}{0}", vbCrLf)
      sb.AppendFormat("Espero que así lo tengas más fácil...{0}Gracias por hacerme el trabajo más fácil.{0}", vbCrLf)
      txtFic.Text = sb.ToString
      '
   End Sub
   '
   ' guardar los nuevos valores en la configuración
   Private Sub fFiltrarHTML_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
      cfgSetValue("configuration/appSettings", "chkADO.Checked", Me.chkADO.Checked.ToString)
      cfgSetValue("configuration/appSettings", "chkAPI32.Checked", Me.chkAPI32.Checked.ToString)
      cfgSetValue("configuration/appSettings", "chkASP.Checked", Me.chkASP.Checked.ToString)
      cfgSetValue("configuration/appSettings", "optCS.Checked", Me.optCS.Checked.ToString)
      cfgSetValue("configuration/appSettings", "optNET.Checked", Me.optNET.Checked.ToString)
      cfgSetValue("configuration/appSettings", "optVB6.Checked", Me.optVB6.Checked.ToString)
      cfgSetValue("configuration/appSettings", "optVBNET.Checked", Me.optVBNET.Checked.ToString)
      cfgSetValue("configuration/appSettings", "txtDescripcion.Text", Me.txtDescripcion.Text)
      cfgSetValue("configuration/appSettings", "txtDescripcion.Text", Me.txtDescripcion.Text)
      cfgSetValue("configuration/appSettings", "txtTitulo.Text", Me.txtTitulo.Text)
      cfgSetValue("configuration/appSettings", "txtZip.Text", Me.txtZip.Text)
      '
      If Me.WindowState = FormWindowState.Normal Then
         cfgSetValue("configuration/appSettings", "Form1.Left", Me.Left.ToString)
         cfgSetValue("configuration/appSettings", "Form1.Top", Me.Top.ToString)
      End If
      '
      configXml.Save(ficConfig)
   End Sub
   '
   Private Sub asignarCampos(ByVal sender As System.Object, ByVal e As System.EventArgs) _
               Handles optNET.CheckedChanged, optVBNET.CheckedChanged, _
                     chkASP.CheckedChanged, chkADO.CheckedChanged, chkAPI32.CheckedChanged, _
                     optVB6.CheckedChanged
      panelNET.Enabled = optNET.Checked
      optVBNET.Enabled = optNET.Checked
      optCS.Enabled = optNET.Checked
      If optNET.Checked AndAlso optCS.Checked = False AndAlso optVBNET.Checked = False Then
         optVBNET.Checked = True
      End If
      '
      Dim s As String = ""
      '
      If optNET.Checked Then
         If txtTitulo.Text = "" OrElse txtTitulo.Text.EndsWith(":") Then
            txtTitulo.Text = "Colabora.NET:"
         End If
         If optVBNET.Checked AndAlso Me.optCS.Checked Then
            s &= ".NET; VB; C#"
         ElseIf optVBNET.Checked Then
            s &= ".NET; VB"
         ElseIf Me.optCS.Checked Then
            s &= ".NET; C#"
         End If
      Else
         If txtTitulo.Text = "" OrElse txtTitulo.Text.EndsWith(":") Then
            txtTitulo.Text = "Colabora:"
         End If
         s = "VB; VB6"
      End If
      '
      If chkASP.Checked Then
         If Me.optNET.Checked Then
            s &= "; ASP.NET"
         Else
            s &= "; ASP"
         End If
      End If
      '
      If chkADO.Checked Then
         s &= "; Bases"
         If Me.optNET.Checked Then
            s &= "; ADO.NET"
         Else
            s &= "; ADO"
         End If
      End If
      '
      If chkAPI32.Checked Then
         s &= "; API; Win32 API"
         If Me.optNET.Checked Then
            s &= "; Interop; DllImport"
         Else
            s &= "; Declare"
         End If
      End If
      '
      txtKeywords.Text = s
   End Sub
   '
   Private Function cfgGetValue(ByVal seccion As String, _
                         ByVal clave As String, _
                         ByVal predeterminado As String) As String
      '
      Dim n As XmlNode
      n = configXml.SelectSingleNode(seccion & "/add[@key=""" & clave & """]")
      If Not n Is Nothing Then
         Return n.Attributes("value").InnerText
      Else
         Return predeterminado
      End If
   End Function
   '
   Private Function cfgGetValueSection(ByVal seccion As String, _
                              ByVal clave As String, _
                              ByVal predeterminado As String) As String
      ' Si la sección indicada no es la última leída
      ' asignamos un valor nulo para que vuelva a leer la sección
      If seccionAnt <> seccion Then
         valores = Nothing
         seccionAnt = seccion
      End If
      '
      If valores Is Nothing Then
         valores = CType(ConfigurationSettings.GetConfig(seccion), IDictionary)
      End If
      If valores.Contains(clave) Then
         Return valores(clave).ToString
      Else
         Return predeterminado
      End If
   End Function
   '
   ' El método para guardar los valores
   Private Sub cfgSetValue(ByVal seccion As String, _
                     ByVal clave As String, _
                     ByVal valor As String)
      '
      Dim n As XmlNode
      n = configXml.SelectSingleNode(seccion & "/add[@key=""" & clave & """]")
      If Not n Is Nothing Then
         n.Attributes("value").InnerText = valor
      End If
   End Sub
   ' 
   Private Sub btnExaminaZip_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExaminaZip.Click
      ' seleccionar el fichero zip                        (28/Feb/05)
      Dim openFD As New OpenFileDialog
      '
      With openFD
         .Title = "Seleccionar el fichero ZIP"
         .Filter = "Ficheros ZIP (no RAR, por favor) (*.zip)|*.zip|Ficheros RAR (*.rar)|*.rar"
         .FileName = txtZip.Text
         If .ShowDialog = DialogResult.OK Then
            '
         End If
      End With
   End Sub
   '
   Private Sub comprobarTituloEtc()
      ' comprobar los datos del fichero arrastrado            (01/Mar/05)
      ' si es que tiene algo...
      Dim re As Regex
      Dim sTexto As String = txtFic.Text
      Dim m As Match
      '
      ' guardar los <meta keywords, description y seccion
      '
      ' Aquí utilizo Groups(1) para obtener el texto correspondiente
      ' para conseguirlo poner entre paréntesis lo que se quiere "capturar"
      '
      re = New Regex("<meta name\s*=\s*""description""\s*content\s*=(\s*[^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Singleline)
      m = re.Match(sTexto)
      If m.Success Then
         txtDescripcion.Text = m.Groups(1).Value.Replace(ChrW(34), "")
      End If
      re = New Regex("<meta name\s*=\s*""keywords""\s*content\s*=(\s*[^>]*)>", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Singleline)
      m = re.Match(sTexto)
      If m.Success Then
         txtKeywords.Text = m.Groups(1).Value.Replace(ChrW(34), "")
      End If
      re = New Regex("<title>(.+)</title>", RegexOptions.IgnoreCase Or RegexOptions.Compiled)
      m = re.Match(sTexto)
      If m.Success Then
         txtTitulo.Text = m.Groups(1).Value.Replace(ChrW(34), "")
      End If
      '
      '&zip=
      re = New Regex("&zip=(\w+\.zip)", RegexOptions.IgnoreCase Or RegexOptions.Compiled Or RegexOptions.Singleline)
      m = re.Match(sTexto)
      If m.Success Then
         txtZip.Text = m.Groups(1).Value
      End If
   End Sub
End Class

 


la Luna del Guille o... el Guille que está en la Luna... tanto monta...