Programación General > Visual Basic para principiantes

 Podrian Publicar funciones para procesar Cadena de texto

<< < (8/8)

Nebire:

--- Cita de: "m0skit0" ---Lo que me lleva a preguntarles:
¿Qué creen que compensa más: que el código se ejecute más rápido o que sea más legible?  <_<
--- Fin de la cita ---
Interesante pregunta. A título personal (porque de forma general dudo que pueda darse una respuesta exacta.... y que todo el mundo esté de acuerdo) creo que uno tiene que hacer un balance en su código.

Esto es, si tu programa vuela entonces puedes darle más importancia a la legibilidad y la brevedad (a menudo están reñidos otras no), en cambio si el programa adolece de lento, no es plan pretender ser tan legible. a menudo la falta de claridad en un programa la acabamos supliendo con comentarios. También cuenta si tu código ha de pasar por otras manos distintas a las tuyas, ahí la claridad tiene más importancia. Por otro lado a medida que los procesadores son más rápidos y las memorias más grandes tiene menos relevancia la velocidad. Lo importante es que uno sepa fijar el límite.

Por ejemplo uno puede escribir un código denso y oscuro en 5000 líneas y ser muy veloz en cambio quizás puede hacer lo mismo con sólo 500 líneas pero recurriendo por ejemplo a librerías externas. El caso es que 500 líneas será un código más fácil de seguir pero por otro lado al ser las librerías externas implican cierto oscurantismo porque requiere estudiarse esas librerías, si son de uso frecuente como las API de windows, se hace mucho más llevadero pero cuando son de diferentes programas y un puñado de cada uno, tienes menos libertad vas a veces forzado por las limitaciones de las librerías y por la manera en que fueron programadas. entonces comparativamente quizás esas 5000 líneas densas y oscuras quizás compensen sobre esas 500. Pero como digo cada uno en su caso debe sopesarlo. dudo que pueda generalizarse si no es diviiidiendo en grupos e indicar si uno pertenece a ese grupo a tal vez al otro.

Nebire:
Aprovechando que tengo un rato libre voy a exponer una función que es posible que la tengais parecida o muy distinta, nunca se sabe.

La función como comentaba más arriba trata de contar las palabras que tiene un texto. Por comparativa (nuca se me ha ocurrido verificar antes el potencial de esta función) he realizado otra equivalente que al hilo de lo que venimos hablando es más breve pero tiene un rendimiento bastante menor.
A ambas funciones, como se aprecia se han 'inyectado' dentro de un bucle de 1000 reps. para comprobar diferencias ya que si no resulta difícil apreciarlo en su justa medida.


--- Código: Visual Basic ---  Public Function Contar_Palabras1(texto As String) As Long    Dim txt() As String    Dim k As Long ' contador    Dim i As Long ' contador del bucle        ti = Timer    For A = 1 To 1000        txt = Split(texto, " ")        If texto <> "" Then            If UBound(txt) = 0 Then                If Trim$(txt(0)) <> "" Then                    Contar_Palabras1 = 0: GoTo salir ' Exit Function                Else                    Contar_Palabras1 = 1: GoTo salir ' Exit Function                End If            End If        End If                For i = 0 To UBound(txt)            If txt(i) <> "" Then                k = k + 1            End If        Next    Next    Contar_Palabras1 = k salir:    MsgBox Timer - ti End Function  

La siguiente función es bastante menos lógica en cuanto a idearla, sirve de  contraste para la comparativa, usa un bucle do


--- Código: Visual Basic --- Public Function Contar_Palabras2(texto As String) As Long    Dim k As Long  ' contador    Dim p As Long ' posición en la cadena    Dim txt As String '        ti = Timer            For A = 1 To 1000         txt = Trim$(texto)        If txt = "" Then Contar_Palabras1 = 0: Exit Function                Do            p = InStr(txt, " ") ' espacio entre comillas            If p > 0 Then       ' mientras haya espacio entrará aquí...                k = k + 1                txt = Trim$(Mid$(txt, p + 1)) ' elimino la palabra más a la izquierda y quito los espacios extras hasta la siguiente palabra.            Else                  ' cuando no haya más espacios, ya no quedan más palabras, devolvemos el resultado               k = k + 1               Exit Do            End If        Loop    Next    Contar_Palabras2 = k    MsgBox Timer - tiEnd Function  
Puede notarse que si declaamos el parámetro byval la misma variable del parámetro podría usarse en vez de 'txt', que por otro lado ha sido forzado por el bucle de repetición externo.
Aunque parezcan muy similares, lo cierto es que los resultados son bastante diferenciados.

El texto empleado fue un archivo en la carpeta de windows, concretamente el de 'wmsetup.log' que en mi caso pesa 9'13kb. y contiene 1.056 palabras, con el bucle de 1000 repeticiones halló:

1.056.000 ----- 3'7 sg   funcion 1
1.056.000 -----16'01 sg. función 2

El resto del código para probarlo son 2 botones de llamada uno para cada función un label indicando las palabras encontradas y un richtextbox donde se carga el fichero y cuyo texto es el empleado.
El código 'extra' para probarlo es el siguiente:

--- Código: Visual Basic ---     Private Sub Form_Load()    Rtxt.FileName = "C:WINDOWSwmsetup.log"End Sub Private Sub Command1_Click()    Label1.Caption = "Palabras totales= " & Contar_Palabras1(Rtxt.Text)End Sub Private Sub Command2_Click()    Label1.Caption = "Palabras totales= " & Contar_Palabras2(Rtxt.Text)End Sub  

ferhn:
Aca les dejo algo interesante para hacer casi de todo con texto

Esto lo hice dentro de un clase

--- Código: Text --- Dim cTexto As StringDim dLetras As Integer Dim i, SB, J As IntegerDim P() As StringDim POriginal As String 'para las palabrasDim dPalabra As IntegerDim wordCount As Integer            ' Número de palabras en el documento'Dim sourceText As String            ' Contiene el texto del documento para examinarloDim startFound, endFound As Integer ' Banderas para seguir la pista de las palabras encontradasDim thisChar As String'mayusculaDim Mayu As StringDim Minus As StringDim DNormal As StringDim LetraSin As StringDim TextoReves As StringDim Fechas As DateDim Hora As Date Public Property Get CuentaLetras() As String    CuentaLetras = dLetrasEnd Property Public Property Let CuentaLetras(ByVal vNewTexto As String)    cTexto = vNewTexto    dLetras = Len(cTexto)End Property  Public Property Get CuentaPalabra() As String    CuentaPalabra = wordCountEnd Property Public Property Let CuentaPalabra(ByVal vNewValue As String)    ' Inicializar wordCount, offSet, y las banderas "Found"    wordCount = 0: offSet = 1: startFound = False: endFound = False    ' Copiar documento en variable (para examinarlo más rápidamente)            ' Examina cada carácter hasta llegar al final del documento.    Do Until offSet > Len(cTexto)        thisChar = Mid$(cTexto, offSet, 1)        If Not startFound Then            ' Buscar principio de palabra            startFound = isAlphaNumeric(thisChar)            If startFound Then wordCount = wordCount + 1        Else            ' Buscar final de palabra.            endFound = Not isAlphaNumeric(Mid$(cTexto, offSet, 1))            If endFound Then startFound = False: endFound = False        End If        offSet = offSet + 1    Loop            'Visualizar el número de palabras    'MsgBox "Este documento contiene " & wordCount & " palabras."End Property Private Function isAlphaNumeric(anyChar) As Integer    Select Case Asc(anyChar)        Case 65 To 90   'A a Z            isAlphaNumeric = True        Case 97 To 122  'a a z            isAlphaNumeric = True        Case 48 To 57   '0 a 9            isAlphaNumeric = True        Case 193, 225, 201, 233, 205, 237, 211, 243, 218, 250 'Á, É, Í, Ó, Ú, á, é, í, ó, ú            isAlphaNumeric = True        Case 220, 252   'Ü, ü            isAlphaNumeric = True        Case 209, 241   'Ñ, ñ            isAlphaNumeric = True        Case Else            isAlphaNumeric = False    End SelectEnd Function Public Property Get TodoMayus() As String    Mayu = StrConv(cTexto, vbUpperCase)    TodoMayus = MayuEnd Property  Public Property Get TodoMinus() As String    Minus = StrConv(cTexto, vbLowerCase)    TodoMinus = MinusEnd Property  Public Property Get Normal() As String    Normal = DNormalEnd Property Public Property Let Normal(ByVal vNewValue As String)    DNormal = vNewValueEnd Property  Public Property Get PalabraExtraida(Text1 As TextBox, Numero As Integer)    Dim SB, J As Integer        SB = 1        For i = 1 To Len(Text1)                If Mid(Text1, i, 1) <> " " Then                    ReDim Preserve P(SB)                    P(SB) = P(SB) & Mid(Text1, i, 1)                    J = i                Else                    Do While Mid(Text1, i, 1) = " "                       i = i + 1                    Loop                    i = i - 1                    SB = SB + 1                End If        Next i        If Numero <= SB Then            PalabraExtraida = P(Numero)            For i = 0 To SB - 1                P(i) = ""            Next i        Else            MsgBox "No existe la palabra " & Numero, vbCritical, "Mensaje"            Text1.Text = ""        End IfEnd Property Property Get CantLetras(txtTexto As TextBox)Dim J As IntegerDim SB As IntegerDim S As String                If Len(txtTexto.Text) <= 255 Then            For i = 1 To Len(txtTexto)                S = Mid(txtTexto, i, 1)                If S <> Chr(32) Then                    J = J + 1                End If            Next i            CantLetras = J       End If     CantLetras = CantLetrasEnd Property 'PARA TEXTO REVERSOPublic Property Get TextReverso() As VariantTextoReves = StrReverse(cTexto)    TextReverso = TextoRevesEnd Property Public Property Get Fecha() As DateFechas = Time(Label7.Caption)Fecha = FechasEnd Property Public Property Get Horas() As DateHora = Time(LblHora.Caption)Horas = HoraEnd Property  

Nebire:
Bueno ferhn, tu 'texto' admite varios comentarios....

Primero 2 incisos, el primero es que resulta visiblemente difícil de leer, acostúmbrate a usar el ( quitando las comillas simples)  '['code=vb']'  en vez de '['code=text']'... al colorear se ve mejor donde empizan y acaban las funciones, etc...

El 2º es que parece que has copiado el código de alguien y le has dado unos toques personales, al respecto te señalo que cuando hagas así o dejas todo en 'inglis' o lo cambias todo al español pero eso de tener un 'espanglis' a mi me produce cierta repulsión... encontrasem 'startFound' y 'TextoReves' me parece estar comunicando con un alien que oye cosas no las entiende pero confía en que el que lo reciba si. Esto es sólo una cuestión de estilo, no es algo grave pero da una indicación de el respeto hacia los demás si se adecúa el código, copiar y pegar sólo es señal de dejadez...

y ahora los comentarios...


--- Cita de: "ferhn" ---
Public Property Get CuentaLetras() As String
    CuentaLetras = dLetras
End Property
 
Public Property Let CuentaLetras(ByVal vNewTexto As String)
    cTexto = vNewTexto
    dLetras = Len(cTexto)
End Property
--- Fin de la cita ---
Esto carece de sentido la función len(texto) resuelve el caso,  no necesita por tanto travestirse de propiedad.


--- Cita de: "ferhn" ---
Public Property Get CuentaPalabra() As String
    CuentaPalabra = wordCount
End Property
 
Public Property Let CuentaPalabra(ByVal vNewValue As String)
--- Fin de la cita ---
Aquí varios comentarios, comentario 1 en la parte 'GET' puede verse también en el anterior. Si cuentapalabra suponemos que es una cifra a qué leches viene poner un 'string' ????. Yo te lo digo... a que haces algo impropio, algo impropio es asignar un valor a allgo que realmente no le pertenece, es como vestir a un mono de santo o como poner un remolque a un Formula-1. Al parecer no sabes cuando algo debe ser una propiedad y cuando una función. Yo te lo explico: si cuando introduces un dato es un tipo de datos y cuando debe devolver un dato devuelve un tipo de datos distinto al que se pedía como parámetro, eso es lo que describe una función. si el tipo de datos pasado por parámetro se ha de retener y en otra ocasión se puede pedir y es el mismo tipo de datos, eso es para usar como propiedad... si el parámetro se pasa e inmediatamente hace algo y ese dato no ha de quedar retenido eso es un método...

Por tanto comentario 2: (en la parte LET)  CuentaPalabraS (con S al final porque es plural cuanta muchas no una) debe ser una función... Te voy a decir que puede ocurrir si lo dejas como propiedad... si le pasamos como parámetro un texto de 30 mb. una vez que haya terminado de precesarlo como propiedad que es, guardaría el parámetro hasta que se inroduzca otro, o lo que es lo mismo, estarías reteniendo en memoria inútilmente datos que no se necesitan ya... tampoco hace falta que sea  30 Mb. para que esto sea una estupidez, pongo 30Mb. para que se vea claramente que lo es.

comentario: 3 Una propiedad debe retener 'memorizado' uno de sus parámetros, si se le pasa x parámetros y lo que retiene no es ninguno de ellos realmente no es una propiedad, es nuevamente una función si yo tengo la propiedad: Color_de_Pelo lo lógico es que el parámetros sea un color y adicionalmente otro u otros parámetros si fueran necesarios, pero la propiedad alamcenará el color tal como indica su nombre y al rescatar la propiedad será dicho valor el que he de devolver, si la propiedad es color_de_Pelo y le paso como parámetros 5 dedos, 2 pies y 3 camisas pero nunca el color del pelo, habrá alguien que sepa utilizar esa 'propiedad' ...?  realmente habría que llamarle monstruosidad...

comentario 4 el uso que se hace de esa función (CuentaPalabras) es dudoso y te explico porqué, recurre a la función 'isAlphaNumeric', para determinar ciertos casos, esto es algo relativo, es decir si exponemos un criterio para definir palabras distinto que estar separado blanco lo podremos utilizar perfectamente pero ya no podremos darle el carácter 'universal' de contar palabras, sino dado que es un caso relativo , relativizarlo así el nombre debería ser cambiado a por ejemplo 'ContarMisPalabras' lo cual ya hace referencia a un modo exclusivo y particular de realizar la cuenta. Y esto sin siquiera entrar a evaluar lo que sea que haga dicha función 'isAlphaNumeric'. Realmente una función de contar palabras podría ser tan simple como:


--- Código: Visual Basic --- public function Contar_Palabras(texto as string) as long    dim s() as string, n as long     if len(texto)=0 then           Contar_Palabras=0   else         if instr(texto," ")<>0 then             s=split(texto)            ' este bucle es necesario porque split corta por 1 espacio, es decir después de encontrar un espacio el siguiente carácter lo interpreta como una cadena             for k=0 to  ubound(s )                            if s(k)<>"" then n=n +1             next             Contar_Palabras=  n        else             Contar_Palabras=1        end if    end ifend function  
Desde luego esto de contar palabras sigue siendo relativo, me explico esto es aplicable desde el punto de vista de la programación, pero para otros propósitos la lista debe volver a filtrarse, por ejemplo un retorno de carro (enter) puede aparecer unido al final de la apalabra anterior y la primera palabra de la siguiente línea sio no se dejó espacio al final de la misma. También, interpretamos una coma o un punto como una palabra ?, y los signos =,<,(, etc... y si una palabra está unida a operadores? por ejemplo: 'Velocidad=e/t' daría un valor diferente de 'Velocidad =e/t' y diferente de 'Velocidad = e / t', por eso para casos reales, contar plabaras es siempre una rutina complaja y que debe llevar aparejado un método a usar como parámetros donde en dicho/s parámetro/s se especifican las condiciones de lo que es una plabara y lo que no. En dicho caso el código presentado anteriormente presenta la 1ª fase, una vez determinado que el texto tiene más de una palabras, la matriz obtenida debe filtrarse sucesivamente por otra/s rutina/s específicas, lo ideal es que no haya que pasar la matriz para cada caso si no que una misma función analice varios casos relativos a un mismo tema en el mismo bucle... pero en general la rutina que presentas no debe inferirse como lo que su nombre indica, por las razones explicadas.


comentario 5 La función isAlphaNumeric (cada uno debe acomodarlo a como le valga) puede simplicarse mucho más, tanto como reducirlo todo a sólo 2 casos, pués sólo existen 2 casos, TRUE-FALSE, usando el mismo código te lo resumo:

--- Código: Visual Basic --- Private Function isAlphaNumeric(anyChar) As Integer    Select Case Asc(anyChar)        Case 48 - 57,  65 - 90, 97-122, 193, 225, 201, 233, 205, 237, 211, 243, 218, 250, 220, 252 , 209, 241               isAlphaNumeric = True       case else            isAlphaNumeric=false   end select end function    
te ahorras montón de líneas inútiles y queda más claro, al hacer varios case, a primera vista parece que en cada uno hará una cosa distinta, y eso confunde.

comentario 6 estas funciones:

--- Cita de: "ferhn" --- Public Property Get TodoMayus() As String ...   End Property
Public Property Get TodoMinus() As String ... End Property
--- Fin de la cita ---
Son inútiles por redundantes, como ya se dijo antes una función que resuleve un caso no debe trasvestirse, para hacer lo mismo pero ralentizándolo...


comentario 7 Esto creo que debo llevarlo a un laboratorio a analizar.... yo aún no he sido capaz de encontrarle sentido.

--- Citar ---Public Property Get Normal() As String
    Normal = DNormal
End Property
 
Public Property Let Normal(ByVal vNewValue As String)
    DNormal = vNewValue
End Property

--- Fin de la cita ---

comentario 8

--- Cita de: "ferhn" ---
Public Property Get PalabraExtraida(Text1 As TextBox, Numero As Integer)

--- Fin de la cita ---
Te complicas en exceso, para eso existe la función INSTR . Con instr vas comprobando donde empiza y terminan las palabras... ya que leer carácter a carácter es bastante lento, conviene delegar en una función más potente o recurrir a la API, para textos de pocas palabras puede valerte pero si por ejemplo tratas de buscar una texto en un dado número de ficheros la búsqueda sería muy lenta.

comentario 9 como ya dije anteriormente trasvestir una función es perder tiempo y tratar de convertirlo en una propiedad una aberración.

--- Cita de: "ferhn" ---
Public Property Get TextReverso() As Variant
TextoReves = StrReverse(cTexto)
    TextReverso = TextoReves
End Property

--- Fin de la cita ---

en cuanto a las fechas,  :wub:  sin comentarios...

Así que por favor en cuanto puedas corrige todo el texto o retíralo,  :hitcomp:  ya que no es precisamente un ejemplo sino de mala programación. La frase:
--- Cita de: "ferhn" ---    Aca les dejo algo interesante para hacer casi de todo con texto
--- Fin de la cita ---
francamente resulta desacertada aparte de queen cuanto a completitud no representa nada.
 
Espero que no te lo tomes a mal sino como una orientación de que no se debe hacer   :beer:

Navegación

[0] Índice de Mensajes

[*] Página Anterior

Ir a la versión completa