elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


 


Tema destacado: Sigue las noticias más importantes de seguridad informática en el ttwitter! de elhacker.NET


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP) (Moderador: kub0x)
| | | |-+  [Duda C#]Suma y Resta en un String
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: [Duda C#]Suma y Resta en un String  (Leído 705 veces)
Reent

Desconectado Desconectado

Mensajes: 52



Ver Perfil
[Duda C#]Suma y Resta en un String
« en: 26 Febrero 2020, 11:48 »

Hola a todos!

Quiero hacer una suma y resta en un solo string. Solo que la idea que tengo por el momento solo me deja hacer una de las 2 cosas...

Código
  1. public void OnNumberPressed(object param)
  2.        {
  3.  
  4.            if (param.ToString() == "c")
  5.            {
  6.                Input = "";
  7.            }
  8.            else if (param.ToString() == "=")
  9.            {
  10.                string[] res = Input.Split(new char[] { '+', '-' }, StringSplitOptions.RemoveEmptyEntries);
  11.            }
  12.            else
  13.            {
  14.                Input += param.ToString();
  15.            }
  16.  
  17.            if (param.ToString() == "+")//aqui quiero que los numeros positivos se separen en un char array
  18.            {
  19.  
  20.            }
  21.            else if (param.ToString() == "-")// Lo mismo aqui
  22.            {
  23.  
  24.            }
  25.        }
  26.  

ejemplo: "10+20-13+10"
char[] numPos {10,20,10};
char[] numNeg {13};

Si alguien tiene alguna idea, me vendria bien una mano.

Saludos!

[MOD] Usar la etiqueta GeSHi adecuada.


« Última modificación: 26 Febrero 2020, 14:53 por simorg » En línea

ThunderCls


Desconectado Desconectado

Mensajes: 432


Coder | Reverser | Gamer


Ver Perfil WWW
Re: [Duda C#]Suma y Resta en un String
« Respuesta #1 en: 26 Febrero 2020, 18:26 »

En estos casos las expresiones regulares son tus aliadas

Código
  1. (?<positivos>[^-\w\s]\d*)|(?<negativos>[^+\w\s]\d*)

En el grupo "positivos" tendrias los numeros positivos y en el grupo "negativos" los negativos

Suerte


En línea

-[ "…I can only show you the door. You're the one that has to walk through it." – Morpheus (The Matrix) ]-
http://reversec0de.wordpress.com
https://github.com/ThunderCls/
Reent

Desconectado Desconectado

Mensajes: 52



Ver Perfil
Re: [Duda C#]Suma y Resta en un String
« Respuesta #2 en: 27 Febrero 2020, 14:26 »

Gracias al mod!! no sabia que esa funcion existia.

@Thunder

tu idea la entendi pero tu codigo no.
En línea

ThunderCls


Desconectado Desconectado

Mensajes: 432


Coder | Reverser | Gamer


Ver Perfil WWW
Re: [Duda C#]Suma y Resta en un String
« Respuesta #3 en: 27 Febrero 2020, 14:41 »

tu idea la entendi pero tu codigo no.

Solo te he pasado la expresion regular que debes usar, todo lo que tienes que hacer es usarla en tu lenguaje

https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netframework-4.8
En línea

-[ "…I can only show you the door. You're the one that has to walk through it." – Morpheus (The Matrix) ]-
http://reversec0de.wordpress.com
https://github.com/ThunderCls/
EdePC
Colaborador
***
Desconectado Desconectado

Mensajes: 1.393



Ver Perfil
Re: [Duda C#]Suma y Resta en un String
« Respuesta #4 en: 27 Febrero 2020, 22:36 »

- Wow, me he hecho líos para realizarlo usando RegEx y Split, en mis libros de Visual Basic .NET no hay nada de Expresiones Regulares, he tenido que echar mano de mis libros de C# donde se toca el tema en detalle. De momento solo tengo Visual Basic .NET 2005 y lo he implementado así:

Código
  1. Imports System.Text.RegularExpressions
  2.  
  3. Public Class Form1
  4.  
  5.  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn.Click
  6.    Dim rx As New Regex("(?<negativos>-\d+)|(?<positivos>\d+)")
  7.    Dim positivos As String = ""
  8.    Dim negativos As String = ""
  9.    For Each match As Match In rx.Matches(txt.Text)
  10.      If match.Groups("positivos").Value <> "" Then
  11.        positivos = positivos & "," & match.Value
  12.      Else
  13.        negativos = negativos & "," & match.Value
  14.      End If
  15.    Next
  16.    Dim numPos() As String = positivos.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
  17.    Dim numNeg() As String = negativos.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
  18.  End Sub
  19. End Class

- He usado una RegEx más corta, me parece que le basta ..., luego voy concatenando una String para los positivos y otra para los negativos, unidas mediante una "coma", al final se usa esa misma coma para hacerle un Split quitando las vacias.

- Tengo entendido que pasarlo a C# es bastante sencillo, haber si me llega a descargar el C# 2005 para mañana y pasarlo si es que aún hay dudas.
En línea

**Aincrad**


Desconectado Desconectado

Mensajes: 506



Ver Perfil
Re: [Duda C#]Suma y Resta en un String
« Respuesta #5 en: 27 Febrero 2020, 23:00 »

- Tengo entendido que pasarlo a C# es bastante sencillo, haber si me llega a descargar el C# 2005 para mañana y pasarlo si es que aún hay dudas.

Siempre puedes usar el conversor de Telerik Code Converter

Nunca falla, yo mismo he pasado codigos de C# a vb . y funcionan correctamente.

Codigo Convertido :

Código
  1. using System;
  2. using System.Text.RegularExpressions;
  3.  
  4. public class Form1
  5. {
  6.    private void Button1_Click(System.Object sender, System.EventArgs e)
  7.    {
  8.        Regex rx = new Regex(@"(?<negativos>-\d+)|(?<positivos>\d+)");
  9.        string positivos = "";
  10.        string negativos = "";
  11.        foreach (Match match in rx.Matches(txt.Text))
  12.        {
  13.            if (match.Groups["positivos"].Value != "")
  14.                positivos = positivos + "," + match.Value;
  15.            else
  16.                negativos = negativos + "," + match.Value;
  17.        }
  18.        string[] numPos = positivos.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  19.        string[] numNeg = negativos.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  20.    }
  21. }
En línea


ThunderCls


Desconectado Desconectado

Mensajes: 432


Coder | Reverser | Gamer


Ver Perfil WWW
Re: [Duda C#]Suma y Resta en un String
« Respuesta #6 en: 28 Febrero 2020, 00:29 »

- He usado una RegEx más corta, me parece que le basta ..., luego voy concatenando una String para los positivos y otra para los negativos, unidas mediante una "coma", al final se usa esa misma coma para hacerle un Split quitando las vacias.

Tienes razon, la expresion se puede simplificar. Algun motivo por el que no usas un List/ArrayList directamente? En mi opinion la concatenacion/split de cadenas estaria de mas.

Código
  1. public int ExtractNumbersFromString(string input, ref ArrayList positives, ref ArrayList negatives)
  2. {
  3.    Regex rx = new Regex(@"(?<positivos>\d+)|(?<negativos>-\d+)");
  4.    MatchCollection matches = rx.Matches(input);
  5.    foreach (Match match in matches)
  6.    {
  7.        if (!string.IsNullOrEmpty(match.Groups["positivos"].Value))
  8.        {
  9.            positives.Add(match.Value);
  10.        }
  11.        else
  12.        {
  13.            negatives.Add(match.Value);
  14.        }
  15.    }
  16.  
  17.    return matches.Count;
  18. }

Saludos

Edit: Supongo que seria mas util devolver la cantidad de matches en lugar de un bool  :silbar:
« Última modificación: 28 Febrero 2020, 00:32 por ThunderCls » En línea

-[ "…I can only show you the door. You're the one that has to walk through it." – Morpheus (The Matrix) ]-
http://reversec0de.wordpress.com
https://github.com/ThunderCls/
NEBIRE


Desconectado Desconectado

Mensajes: 2.335


Ver Perfil
Re: [Duda C#]Suma y Resta en un String
« Respuesta #7 en: 28 Febrero 2020, 01:31 »

Es mucho más potente (y sobre todo cómodo cuando la gente no domina las expresiones regulares), realizar un automáta que haga justo la parte que se precisa...

Podremos reconocer algo tan complejo como:  " 22  -134 +45 - 087 +170 voy a beber +44j82k"
cuya salida sería: 22 -134 +45 -87 +170 +44 +82 = lo que sume
 " +  232"= 232
 "+23" = 23
 "23   " = 23
 "  23"  = 23
 " 2323tf" = 2323
 " ++++23" = 23
 " +-+-+23" = 23
 " +-+-23" = -23
 " --- 23ffhj"= -23
 " 23.34" = +23  +34 (OJO: no se ha contemplado reconocer decimales, ni con punto ni con coma).
...etc... con negativos...

...cosa que para una expresión regular sería más complejo, dada una falta de uniformidad en el texto...
Nótese que si hay números en el ejemplo que no debieran ser reconocidos, debe ser expresado en las reglas más abajo de la forma conveniente... Como es un ejemplo, no voy a abordarlo en profundidad, lo dejo simple pero que se entienda y el interesado que lo amplíe a sus necesidades. Es decir, no considero 3 casos: decimales ni separadores de miles, tampoco otras bases numéricas que la decimal, una vez entendido el ejemplo, no debería resultar complicado al interesado ampliarlo para admitir tales casos.

Las reglas para número son (uno debe ternerlas claro y hacer los cambos precisos):
 regla "=" componentes     // comentario
--------------------------------------------
 entero = [signo] [spcs] digitos   // el signo es opcional y puede haber o no espacios entre el signo y los digitos
 signo = (positivo|negativo)
 positivo = "+"     // en ausencia de '-' se entenderá que es positivo.
 negativo = "-"
 spcs = espacio [spcs]      // uno o más espacios
 espacio = " "
 digitos = digito [digitos]    // uno o más dígitos
 digito = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9" // los digitos decimales, aunque si fuera preciso podrían separararse por bases numéricas, y reconocer números hexadecimales, binarios, octal, etc...

* Como es un ejemplo, no contemplo números con signo (en el pseudocódigo, aquí sería modificar numero y reconocer el caracter separador del decimal. Se ha elegido como separador decimal, la comilla simple como usamos en español (cambiese al gusto).
  numero =  [signo][spcs] digitos  ["'" digitos]   // un número es un entero o un decimal.

* Tampoco contemplo separadores de miles, con las mismas consideraciones que para decimales, se ha elgido el punto como se acostumbra a usar en español:
  entero = [signo][spcs] gruposDig
  gruposDig = primeGrpDig [gruposDigitos]
  primeGrpDig = digito [[digito] digito]      //esto es 1, 2 ó 3 digitos
  gruposDigitos = grupoDigitos [gruposDigitos]   // uno o más grupos de 3 digitos
  grupoDigitos = ["."] digito digito digito   // 3 digitos antecedidos o no, por un punto.

El peudocodigo pués empieza por una enumeración y luego un array que contenga a dicha enumeración.
Código:
enumeracion TokenDeNumero  //tipo byte
    TOKEN_DESCONOCIDO = 0
    TOKEN_SEP_ESPACIO = 1
    TOKEN_DIGITO = 2
    '
    TOKEN_SIGNO = 4                  // para no disitnguir positivo de negativo, si no solo un signo.
    TOKEN_SIGNO_POS = 5
    TOKEN_SIGNO_NEG = 6
    // otros token separadores que se quieran considerar.
fin enumeracion

Array CharsToken(0 a 255)  // uno por cada byte...

funcion Inicializar
    byte k

    CharsToken(32) = TOKEN_SEP_ESPACIO   // el espacio es el 32, el espacio duro el 160, aquí se ignora...

    bucle para k desde 48 a 57
        CharsToken(k) = TOKEN_DIGITO         // dígitos del 0 al 9.
    siguiente

    CharsToken(43) = TOKEN_SIGNO_POS
    CharsToken(45) = TOKEN_SIGNO_NEG
    
    // y eso es todo, el resto de caracteres son ignorados... tienen valor 0 en el array.
fin funcion

Ahora las funciones de reconocimeinto del número:
Código:
// Si devuelve true, valor contiene un número en caso contrario, se debe ignorar
Buleano = Funcion SiguienteToken(arraybytes Data(), porreferencia entero Indice, porreferencia entero Valor)
    TokenDeNumero tkn
    buleano negativo  // false de entrada

    Si SaltarEspaciosEIgnorarDesconocidos(data, indice) = FALSE devolver FALSE
 
    tkn = CharsToken(data(indice))
    Hacer mientras ( tkn  AND TOKEN_SIGNO)
        si (tkn AND TOKEN_SIGNO) luego
            negativo  = (tkn = TOKEN_SIGNO_NEG) //true si el signo es negativo
            indice += 1
            Si SaltarEspacios(data, indice) = FALSE devolver FALSE  
            tkn = CharsToken(data(indice))
            si (tkn = TOKEN_DIGITO)
                salir del bucle
            sino
                negativo  = FALSE    // se invalida el resultado previo, hay caracteres desconodicos tras el signo que se encontró.
                Si SaltarEspaciosEIgnorarDesconocidos(data, indice) = FALSE devolver FALSE  
            fin si
        fin si
    repetir   ' es un  bucle porque podría ser falsos positivos, casos como: "+   qwrt +asd -zxc ... pero saltarían aquí +   23"
    
    ' si no es negativo, se asume que es positivo.
    si (negativo = TRUE)
         valor = - Data(indice) // [b]ojo: si el valor es 0[/b]... dejo a tu esfuerzo resolver el caso.
    Sino
         valor = Data(indice)
    fin si
    
    si (indice < Data.Length)
        indice += 1
        Hacer mientras (data(indice) = TOKEN_DIGITO)
            indice += 1
            valor *= 10 + data(indice)
            si (indice = Data.Length) Salir del bucle
        repetir
    fin si

    Devolver TRUE  //y valor contiene el valor correcto, si devuelve false, se ignora el valor que contenga...
fin funcion

// Esta función y la siguiente son casi iguales, y no es baladí asignar el valor 0 a desconocidos y 1 al espacio...
// solo salta espacios,
//  Este caso está permitido solo entre signo y digitos: entero = [signo][spcs] digitos
Buleano = Funcion SaltarEspacios(arraybytes Data(), porreferencia entero Indice)
    Hacer mientras (CharsToken(Data(indice)) =  TOKEN_SEP_ESPACIO)
        indice += 1
        si (indice = Data.Length) Devolver FALSE   //final del array salimos d ela función.
    repetir
    
    Devolver TRUE
fin funcion

// esta funcion ignora espacios y caracteres desconocidos.
//  Este caso está permitido cuando termina un número y hasta que comience otro.
Buleano = Funcion SaltarEspaciosEIgnorarDesconocidos(arraybytes Data(), porreferencia entero Indice)
    Hacer mientras (CharsToken(Data(indice)) <= TOKEN_SEP_ESPACIO)
        indice += 1
        si (indice = Data.Length) Devolver FALSE   //final del array salimos de la función.
    repetir

    Devolver TRUE
fin funcion

y finalmente la función que interesada en ello:

Código:
entero = funcion ParseStringToSumasYRestas(arrayBytes Data() )
    entero total, valor, indice
    
    Hacer mientras SiguienteToken(Data, Indice, valor ) = TRUE
        total += valor
        indice +=1
        si (indice = Data.Length) salir dle bucle
    repetir      
    
    Devolver total
fin funcion

Esto siempre será más veloz que una expresión regular, además recoge, casos muy distintos de lo que se considera números, que contemplarlos en una expresión regular complicacría y por tanto ralentizaría su resultado. Claro que usarlo o no, depende de si es muy necesario o no, a veces un código menos eficiente (sin llegar a ser deficiente), expresado en 4 líeas e spreferible a otro más eficiente exresado en 200 líneas:
 " +  232"=232
 "+23" = 23
 "23   " = 23
 "  23"  = 23
 " 2323tf" = 2323
 " ++++23" = 23
 " +-+-+23" = 23
 " +-+-23" = -23
 " --- 23ffhj"= -23
 " 23.34" = +23  +34 (OJO: no se ha contemplado reconocer decimales, ni con punto ni con coma).
...etc... con negativos...

Por último, notar que en el pseudocódigo tampoco se ha contemplado la posibiidad de desbordamiento, evidentemente un número declarado de tipo entero, dará desbordamiento si se intenta parsear con "987654321987654321987654321".
Se supone que son valores coherentes 'sumables', en un rango fijado a ser aceptado en el tipo de datos numérico apropiado.
Si fuera el caso, podría llevarse una cuenta de los dígitos que se van hallando y cuando se alcance uno más de lo permitido devolver un error... si se contempla posibles errore,s la funció debería llamarse TryParse... y no Parse...


p.d.: Añado nota, para despistados: "// ojo: si el valor es 0... dejo a tu esfuerzo resolver el caso."
« Última modificación: 28 Febrero 2020, 01:44 por NEBIRE » En línea

**Aincrad**


Desconectado Desconectado

Mensajes: 506



Ver Perfil
Re: [Duda C#]Suma y Resta en un String
« Respuesta #8 en: 28 Febrero 2020, 01:51 »

@NEBIRE eres el dios del Pseudocodigo ? :v
En línea


NEBIRE


Desconectado Desconectado

Mensajes: 2.335


Ver Perfil
Re: [Duda C#]Suma y Resta en un String
« Respuesta #9 en: 28 Febrero 2020, 14:53 »

Bueno, lo hice del tirón y con prisas pués tenía sueño.
Ahora despejado del cansancio y con más calma veo que se me han escapado algunos detalles... saco un tiempo y lo corrijo.



pongo corregido como cita, para colorear donde haya cambios (las tiquetas code, no dejan, y (razonablemente) no hay geshi para pseudocodigo.
Citar
// Si devuelve true, valor contiene un número en caso contrario, se debe ignorar
Buleano = Funcion SiguienteToken(arraybytes Data(), porreferencia entero Indice, porreferencia entero Valor)
    TokenDeNumero tkn
    buleano negativo  // false de entrada

    Si SaltarEspaciosEIgnorarDesconocidos(data, indice) = FALSE devolver FALSE
 
    tkn = CharsToken(data(indice))
    si (tkn AND TOKEN_SIGNO) luego  // <--- este condicional debía ir por encima del bucle
        Hacer
            negativo  = (tkn = TOKEN_SIGNO_NEG) //true si el signo es negativo
            indice += 1
            Si SaltarEspacios(data, indice) = FALSE devolver FALSE  
            tkn = CharsToken(data(indice))
            si (tkn = TOKEN_DIGITO)
                salir del bucle
            sino
                negativo  = FALSE    // se invalida el resultado previo, hay caracteres desconodicos tras el signo que se encontró.
                Si SaltarEspaciosEIgnorarDesconocidos(data, indice) = FALSE devolver FALSE  
                tkn = CharsToken(data(indice)) // <----linea olvidada
            fin si        
        repetir mientras ( tkn  <> TOKEN_DIGITO)   // <---- la condición de reentrada va mejor abajo
        // visto que al inicio entra si signo, y repite hasta encontrar un dígito, es básicamente lo mismo pero queda más claro así
    fin si
    
    // proveo la solución a los dígitos '0' a la derecha (simplemente se filtran antes):
    Hacer mientras (data(indice) = 48)   // 48 es el valor ASCII del cero.
        indice += 1
        si (indice = Data.Length) devolver FALSE
    repetir
    
    si (indice < Data.Length)  // <--- el bucle anterior anula su necesidad
        indice += 1  //  ídem     "  ----------  "  --------------- " ídem
    
    Si (CharsToken(data(indice)) = TOKEN_DIGITO)  // tras los ceros, podría haber caracteres no dígitos, se resolverá en otra llamada
        Hacer
            indice += 1
            valor *= 10 + (data(indice) - 48)   // <---- Faltaba el -48, tratamos con valores ASCII...
            si (indice = Data.Length) Salir del bucle
        repetir mientras (CharsToken(data(indice)) = TOKEN_DIGITO)   // <--- faltaba el CharsToken(...) para obtener el tipo de token, si no evaluabamos un byte...

        // si no es negativo, se asume que es positivo.
        si (negativo = TRUE)  valor = - valor  // <--- este condicional es preferible bajo el bucle de digitos,
        // (para no complicar la simplicidad del bucle), si no,  daría error con negativos:    ejemplo: -87; -->  -8 * 10 + 7 = -73; --> -73 es distinto de -87
    
        Devolver TRUE  //y valor contiene el valor correcto, si devuelve false, se ignora el valor que contenga...
    sino
        Devolver FALSE
    fin si
fin funcion

en la siguiente función simplemente sobra una línea:
Citar
entero = funcion ParseStringToSumasYRestas(arrayBytes Data() )
    entero total, valor, indice
    
    Hacer mientras SiguienteToken(Data, Indice, valor ) = TRUE
        total += valor
        indice +=1 <--- sobra esta línea.
        si (indice = Data.Length) salir del bucle  //  <--- esta línea no sobra, pero podrría omitirse si se recibe info extra de vuelta
        // el último dígito de un número podría ser también el último del string...
    repetir      
    
    Devolver total
fin funcion

Finalmente indicar que es posible optimizarlo más... si uno se fija bien, podría llegar a haber un chorro de multiplicaciones "*10", tantos como dígitos haya, por cada número... técnicamente solo es necesario una única multiplicación, el resto pueden ser convertidas en sumas. Tiene su tiempito hacer dicha modificación, por lo que lo dejo al esfuerzo de los interesados...  
« Última modificación: 28 Febrero 2020, 16:32 por NEBIRE » En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines