[Duda] - Tratamiento de dos cadenas y comparacion

Iniciado por dont'Exist, 12 Abril 2017, 06:04 AM

0 Miembros y 1 Visitante están viendo este tema.

dont'Exist

Buenas noches a todos. Les hago una pregunta.

Tengo en un formulario un TextBox (oculto) un texto en el cual está correctamente escrito, sin errores. Y otro TextBox el cual se ve, en el cual debo intentar escribir lo que está en el TextBox oculto lo más correctamente posible.

De no estar correctamente escrito en este último, que me cuente la cantidad de errores existentes y si es posible, también marcar cuáles fueron los errores.

¿Es posible hacer esto desde VB.NET?

Vi en algunas páginas proyectos hechos donde implementan RichTextBox, y en otros casos algo relacionado con XAML, pero la verdad es que no he conseguido salir de este problema.

Espero que me puedan, al menos orientar de cómo hacerlo en el caso de que sea posible.

PD: Mi idea es intentar hacer algo parecido a lo que es el programa de mecanografía Typing Master en una de sus funciones cuando compara y muestra los errores, como para que tengan una idea de lo que intento realizar.

Muchas gracias a todos, saludos!

Serapis

#1
Cita de: dont'Exist en 12 Abril 2017, 06:04 AM
Tengo en un formulario un TextBox (oculto) un texto en el cual está correctamente escrito, sin errores. Y otro TextBox el cual se ve, en el cual debo intentar escribir lo que está en el TextBox oculto lo más correctamente posible.

De no estar correctamente escrito en este último, que me cuente la cantidad de errores existentes y si es posible, también marcar cuáles fueron los errores.
Básicamente eso es lo que hace el juego del Mastermind. Lo único que cambia es que en el mastermind, se usan bolas de colores y tu usas letras y bueno, como es un juego se da un límite máximo de intentos.
Guglea si qieres buscando código.

Cita de: dont'Exist en 12 Abril 2017, 06:04 AM
¿Es posible hacer esto desde VB.NET?
Qué, cómo.?????????

Cita de: dont'Exist en 12 Abril 2017, 06:04 AM
Vi en algunas páginas proyectos hechos donde implementan RichTextBox, y en otros casos algo relacionado con XAML, pero la verdad es que no he conseguido salir de este problema.
Se puede complicar uno la vida todo lo que quiera, pero basta con tu idea original, incluso sin siquiera ese textbox oculto, basta que esté en una variable del código.

Cita de: dont'Exist en 12 Abril 2017, 06:04 AM
PD: Mi idea es intentar hacer algo parecido a lo que es el programa de mecanografía Typing Master en una de sus funciones cuando compara y muestra los errores, como para que tengan una idea de lo que intento realizar.
Ahora mismo, no caigo en cual es es eprograma (hay tantos...). Pero ya te digo, que lo que quieres hacer es el típico mastermind, pero más simplificado aún.

Una idea aproximada de lo que tienes que hacer:

- Crear una propiedad que indique el tamaño (númeor de caracteres de la palabra). (esto puede ser una opción en un menú o bien con un control "slider", "scrollhorizontal", etc... siempre entre un rango mínimo y máximo (min=6, Máx=16, por ejemplo).
- Crear una función Nuevo: que genere una palabra al azar del tamaño indicado, y guardarla en un campo oculto, convertida en un array de caracteres.
- Crear una función Intento (llamada desde un botón y con un texto, que yace sobre un control de texto (textbox, es más que sufieciente, si quieres colorealo, para que sea más 'atractivo'...

--- Tu escribes en el texto, en el evento 'change' del textbox, miras si la palaba escrita tiene el largo (ni más ni menos) que se requiere y si es que sí, activas el botón para "Escrutar", si no, sigue desactivado.
--- También puedes dejar siempre activo el botón y no hacer nada en eventos del texto, y cuando se pulse el botón, miras si el texto contiene el númeor de caracteres concreto, si no es así, un mensaje al usuario de 'faltan/sobran letras'... el código del botón.

--- El botón, invoca la función Intento, pasándole el texto que contiene el control si devuelve false, pegar de nuevo el texto 'Palabra' en el textbox.
Y el código de la función lo que hará es:
Funcion Intento(byref Palabra as string) as boolean
--- Recibir un texto del mismo largo que la palabra oculta.
--- Convertirlo a un array de caracteres.
--- Iniciar un bucle, que recorra desde 0 hasta el final del array.
--- Dentro del bucle:
---------- Si Oculto(k) <> TxtUser(k) luego
---------------   TxtUser(k)= "*"
---------------    n +=1
---------- Fin si
--- fin bucle
--- Si n> 0 entonces 'implica que no todos los caracteres fueron encontrados
-------- Convertir el array txtUser que ha sido modificado, indicando con *, cada carácter donde falló, a una cadena de texto, reescribiendo el parámetro: 'Palabra' (se devuelve por referencia).
------------ El botón que recibe de vuelta False, pega entonces el parámetro en el textbox.
--- Si no
-------  Devolver: True
-------  El botón que recibe el true saca un Mensaje: enhorabuena acertaste la palabra oculta...
fin función.


p.d.: Eso sí, antes de todo tú decides si se truncan mayúsculas a inúsculas o viceversa o no... Así :  ¿MARTE=MarTE???, y por tanto obra en consecuencia.
texto= texto.toupper ó texto= texto.ToLower, o nada si se distingue capitalización de caracteres.

Eleкtro

#2
Hola.

Si quieres algo sofisticado entonces lee sobre el algoritmo Diff y el problema LCS (Longest Common Subsequence) e implementa el algoritmo. Existen librerías Diff gratuitas para .NET por lo que no tienes que hacer practicamente nada.

Aparte, lo que pides se puede interpretar de muchas maneras y se puede implementar de infinitas formas dependiendo de las necesidades del programa, así que como no especifiques un poco más siendo breve y conciso aclarando punto por punto como debería comportarse el algoritmo ante cada situación de coincidencia o no coincidencia pues... vamos mal, jeje.

De todas formas te voy a mostrar dos ejemplos que he escrito con los que te puedas hacer una idea de como implementar un algoritmo básico de comparación de cadenas de texto. Ambos ejemplos evaluan las diferencias y usan un RichTextBox para colorear los caracteres que coinciden y los que no, pero ambos ejemplos tienen propósitos distintos para distintos escenarios... pues como ya dije hay infinitas maneras de implementar esto y depende de las necesidades del programa.






El primer ejemplo está enfocado a la evaluación por individual del caracter actual que se haya escrito en el control de edición, esto quiere decir que si modificas otro caracter no se actualizarán las diferencias/colorización del resto de caracteres en el RichTextBox.

Código (vbnet) [Seleccionar]
Public NotInheritable Class Form1 : Inherits Form

   Private ReadOnly Property OrgText As String = "Hello World!"

   Private ReadOnly Property CurText As String
       Get
           If (Me.RichTextBox1 IsNot Nothing) Then
               Return Me.RichTextBox1.Text
           Else
               Return String.Empty
           End If
       End Get
   End Property

   Private Sub RichTextBox1_TextChanged(sender As Object, e As EventArgs) Handles RichTextBox1.TextChanged

       Dim rtb As RichTextBox = DirectCast(sender, RichTextBox)
       Dim chPos As Integer = (rtb.SelectionStart - 1)
       Dim ch As Char = rtb.Text.Substring(chPos, 1)
       Dim diffState As TriState

       If (chPos >= Me.OrgText.Length) Then
           diffState = TriState.UseDefault

       ElseIf (Me.OrgText(chPos) = ch) Then
           diffState = TriState.True

       Else
           diffState = TriState.False

       End If

       ColorizeDifference(rtb, chPos, diffState)

   End Sub

   Friend Shared Sub ColorizeDifference(ByVal rtb As RichTextBox, ByVal charPos As Integer, ByVal diffState As TriState)

       Dim oldSelectionStart As Integer = rtb.SelectionStart
       Dim oldSelectionLength As Integer = rtb.SelectionLength
       Dim fontStyle As FontStyle = rtb.Font.Style

       rtb.SelectionStart = charPos
       rtb.SelectionLength = 1

       Select Case diffState

           Case TriState.True ' El caracter coincide.
               rtb.SelectionColor = Color.YellowGreen
               fontStyle = fontStyle And Not FontStyle.Underline

           Case TriState.False ' El caracter no coincide.
               rtb.SelectionColor = Color.IndianRed
               fontStyle = fontStyle Or FontStyle.Underline

           Case TriState.UseDefault ' El índice del caracter está fuera de rango.
               rtb.SelectionColor = Color.Gray
               fontStyle = fontStyle Or FontStyle.Underline

       End Select

       Using font As New Font(rtb.Font, fontStyle)
           rtb.SelectionFont = font
       End Using

       rtb.SelectionStart = oldSelectionStart
       rtb.SelectionLength = oldSelectionLength
       rtb.ResumeLayout(performLayout:=True)

   End Sub

End Class





El segundo ejemplo está enfocado a la evaluación del texto entero; cada vez que se modifique el texto del RichTextBox se actualizarán las diferencias/colorización de todos los caracteres. Este es el código que he usado en la imagen que he compartido arriba.

Código (vbnet) [Seleccionar]
Public NotInheritable Class Form1 : Inherits Form

   Private ReadOnly Property OrgText As String = "Hello World!"

   Private ReadOnly Property CurText As String
       Get
           If (Me.RichTextBox1 IsNot Nothing) Then
               Return Me.RichTextBox1.Text
           Else
               Return String.Empty
           End If
       End Get
   End Property

   Private Sub RichTextBox1_TextChanged(sender As Object, e As EventArgs) Handles RichTextBox1.TextChanged

       Dim diffIndices As Dictionary(Of Integer, TriState) = GetDifferences(Me.OrgText, Me.CurText)
       ColorizeDifferences(Me.RichTextBox1, diffIndices)

   End Sub

   Friend Shared Function GetDifferences(ByVal orgText As String, ByVal curText As String) As IDictionary(Of Integer, TriState)

       Dim orgChars As Char() = orgText.ToArray()
       Dim curChars As Char() = curText.ToArray()

       Dim orgLength As Integer = orgChars.Length
       Dim curLength As Integer = curChars.Length

       Dim diffIndices As New Dictionary(Of Integer, TriState)(curLength, EqualityComparer(Of Integer).Default)

       For i As Integer = 0 To (curLength - 1)

           If (i < orgLength) Then
               diffIndices.Add(i, (orgChars(i) = curChars(i)))

           Else
               diffIndices.Add(i, TriState.UseDefault)

           End If

       Next i

       Return diffIndices

   End Function

   Friend Shared Sub ColorizeDifferences(ByVal rtb As RichTextBox, ByVal diffIndices As IDictionary(Of Integer, TriState))

       Dim oldSelectionStart As Integer = rtb.SelectionStart
       Dim oldSelectionLength As Integer = rtb.SelectionLength
       Dim fontStyle As FontStyle = rtb.Font.Style

       rtb.SuspendLayout()
       For Each kvp As KeyValuePair(Of Integer, TriState) In diffIndices

           rtb.SelectionStart = kvp.Key
           rtb.SelectionLength = 1

           Select Case kvp.Value

               Case TriState.True ' El caracter coincide.
                   rtb.SelectionColor = Color.YellowGreen
                   fontStyle = fontStyle And Not FontStyle.Underline

               Case TriState.False ' El caracter no coincide.
                   rtb.SelectionColor = Color.IndianRed
                   fontStyle = fontStyle Or FontStyle.Underline

               Case TriState.UseDefault ' El índice del caracter está fuera de rango.
                   rtb.SelectionColor = Color.Gray
                   fontStyle = fontStyle Or FontStyle.Underline

           End Select

           Using font As New Font(rtb.Font, fontStyle)
               rtb.SelectionFont = font
           End Using

       Next
       rtb.SelectionStart = oldSelectionStart
       rtb.SelectionLength = oldSelectionLength
       rtb.ResumeLayout(performLayout:=True)

   End Sub

End Class


¡Saludos!








dont'Exist

Muchas gracias a ambos. Me sirvieron de guía, ahora mismo estoy tratando de ajustarlo a lo que necesito... Aunque tambien estuve probando con RichTextbox.Find() y he obtenido resultados parecidos.

Saludos