[ Foro de Pascal ]

evaluar una expresion...

21-May-2012 17:42
oscar gomez
12 Respuestas

buenas tardes profesor Nacho cabanes y compañeros.
necesito evaluar una expresion que inicialmente contendra variables con valores del 1 al 26 segun corresponda la letra del abecedario(a=1;b=2,c=3,...z=26), cada variable solo aparecera una vez en la expresion.

porejemplo:

a+c-d+b=(1+3-4+2)=2

espero su ayuda y orientacion y ojala este link no quede en el vacio como varios link ya de los cuales he planteado y se han quedado ahi al vacio ..., agradezco si me pueden ayudar.gracias.


21-May-2012 18:38
Antonio P.G.

Hola Óscar.


O sea, digamos que tenemos un array de 26 campos (del 1 al 26) que contienen las letras en orden, ¿no? (Si lo he entendido bien...).

Sea, además, una variable de tipo string, que es la que imputa el usuario (por ejemplo "a+c-d+b").

Entonces tú tendrías que ir leyendo carácter a carácter y:

 - si te encuentras un signo, pones una variable (que podríamos llamar "signo" a 1 o -1.
 - si te encuentras una letra, la buscas en el array y la operas a lo acumulado teniendo en cuenta el signo.

Luego hay algunos otros pequeños detalles, pero la idea básica es esa.

Espero haberte dado algún enfoque.
Ciao.


21-May-2012 23:50
Luis Torres (+12)

Pero, ¿cómo se realizan las operaciones?. Saludos.


22-May-2012 10:07
oscar gomez

Gracias Antonio y luis por permitirme su orientacion y ayuda.

Antonio y como asigno a ese array de 26 campos de letras cada valor, es decir, para que a la letra 'a' le corresponda el 1 (a=1),a la letra 'b' el 2 (b=2),..a la letra 'c' el 3(c=3),...a la letra 'z' el 26( z=26).

para llenar el array con caracteres yo se que puedo hacer:

...

i:integer;
alfabeto:array[1..26] of char;
...

 for i:=1 to 26 do
   alfabeto[i]:=chr(i+96);


de tal forma que alfabeto contendria en este momento:
 alfabeto = a  b  c  d  e  f .... z


pero como hago como te comente al inicio para que a cada letra le corresponda los valores numericos 1, 2, 3, 4, ..26  y poder luego de esta forma hacer las operaciones???

se que la funcion ORD( unCaracter ) devuelve la representación numérica en el código ASCII del caracter unCaracter.


mil gracias por su ayuda .


23-May-2012 19:44
Antonio P.G.

Hola,


¡Ah! Ya se me había olvidado la función "ord()".

Pues ni con array, olvídate de eso; es más sencillo. En vez de un array yo utilizaría esa función.

Imagina que ya tengo la cadena de texto "cadena_texto". Además se sabe que en la posición 0 de un string se almacena su longitud, en forma de letra.

Por otro lado, tenemos una variable, a la que llamaré "suma" y que se arranca en 0.

La idea, más o menos:
********************************************
signo = 1;
suma = 0;
for i:=1 to ord(cadena_texto[0]) do
   si cadena_texto[i] not in ('-','+') entonces
        suma:= suma + signo*(   ord(cadena_texto[i]) - 38  );
   else
        if cadena_texto[i] = '+' entonces
            signo = 1
        else
            signo = -1;
*******************************************

Vale, ahora las notas:
- Lo que he escrito arriba es una chapuza (hay errores varios y mexcla entre código y pseudocódigo...) Blaj!  Lo siento no tengo mucho tiempo.
- Lo del 38 no es una invención mía, pero a lo mejor no es correcto. Hay que ver qué valor numérico le corresponde a la letra 'a'. Creo que era 39, así que si le restas 38, te da 1.
- Asumimos que en la cadena solo hay letras de la 'a' a la 'z' y los signos.
- ¿Dudas?
- Ya que casi está resuelto (a no ser que Nacho diga lo contrario, claro), inténtalo incluyendo, además, letras mayúsculas (para ello puedes diseñar una función que te convierta una mayúscula en minúscula y aplicarla, o a lo mejor ya existe una función en Pascal).


¡Ciao!


23-May-2012 21:07
oscar gomez

gracias antonio por que tu siempre estas pendiente de ayudarnos y con frecuencia lo haces , mil gracias para ti.

antonio dos dudas al respecto:
- cuando haces:
 si cadena_texto[i] not in ('-','+') entonces
       suma:= suma + signo*(  ord(cadena_texto[i]) - 38  );

si el caracter de cadena_texto no esta en el conjunto ['-','+']
que almacena suma? pues me imagino que suma es un integer y supongo que estarias porejemplo para la expresion 'a+b' escogiendo el valor para a inicialmente verdad? luego entraria al
else
       if cadena_texto[i] = '+' entonces
           signo = 1
y despues tomaria el valor para b?
si es asi , que pasaria en el caso que porejemplo se tuviera una expresion como:

'++a-b++? que cambios deberian hacerse en tu esquema inicial antonio?

mil gracias por tu ayuda y amabilidad y por que siempre respondes a nuestros hilos...


24-May-2012 00:09
Antonio P.G.

Cómo va, Óscar.


A ver, básicamente las intrucciones del programa que he planteado como solución son las siguientes:

Tienes una cadena, que está formada por caracteres. Estos caracteres pueden ser de dos tipos: signos o letras minúsculas del alfabeto. Así pues, no pueden ser números, ni letras mayúsculas, ni otros caracteres especiales.

Vas a leer los caracteres de uno en uno, hasta que se acabe la cadena. Si ves un '+', tu signo se volverá positivo, y si ves un '-', tu signo se volverá negativo. Así mismo, si ves una letra, añadirás su valor multiplicado por el valor del signo en ese momento, a tu suma (que comienza en cero).

Intenta seguir el programa tú como si fueses un computador y te hubiesen proporcionado una cadena, y obtendrás tus respuestas.


Ahora bien, te indico aquí algunos ejemplos de lo que mi programa terminaría:

1. ++a-b++ ---> +1-2 suma = -1, signo = 1.
2. +-a-b- ---> -1-2 suma = -3, signo = -1.
3. --a+++-+b ---> -1+2 suma = 1, signo = 1.
4. abc ---> +1+2+3 suma = 6, signo = 1.
5. a-bc ---> +1-2-3 suma = -4, signo = -1.

Como puedes comprobar, si se encuentra un signo, modifica el signo, y si se encuentra una letra, la añade.

Por otro lado, la operación "suma:= suma + signo*( ord(cadena_texto[i]) - 38 );" tiene su origen en que yo sé que "ord('a') = 39". Como las letras van en orden (a, b, c, d, e,..., z), la operación pasará a (39, 40, 41, 41, ...), y tras restarle 38 pasará a (1, 2, 3,...). ¿Ok?

Simplemente, por si quieres ver la tabla ASCII en Pascal, ejecuta este código:

*************************************************
var i:byte;
begin
for i:= 0 to 255 do begin
write (i,'. ',chr(i),' ');
readln;
end.
*************************************************
("chr()" es una función inversa a "ord()"). Ciao!


24-May-2012 18:21
oscar gomez

cordial saludo antonio, gracias por tu explicacion , sin embargo queria preguntar respecto a como seria en el caso real de ese tipo de expresiones donde logicamente cada variable aparezca una vez en la expresion ( asi que a-bc no seria correcto para una expresion a evaluar), donde sabemos que cuando el operador ++ aparece antes de una variable, el valor de esa variable debe incrementarse en uno, antes de que sea usada la variable dentro de la expresion completa, asi porejemplo si tenemos la expresion:
++c-b seria 2 por que c se incrementa a 4 antes de evaluar la expresion entera , asi tambien si el operador ++ aparece despues de la variable, el valor de esta variable debe ser incrementado en uno despues de que su valor sea utilizado para la evaluacion de la expresion asi porejemplo c++-b seria igaul a 1, de igual forma si fuese el caso del operador -- antes o despues.

asi porejemplo en resumen como podria ser el programa para ese tipo de variante que te consulto en este hilo?

ejemplos:

                   a+b =3

                  b-z = 24 ( 2-26 )

                  a+b--+c++= 6

                  f--+c--+d-++e= 7

ojala puedas ayudarme con esto y que el prefesor nacho cabanes nos de su toque brillante e impecable como siempre para poder encontrar la forma de solucionar este tipo de expresiones y que no se olvide de ayudarme u orientarme como siempre ha sido mi intencion. de hecho he podido solucionar muchisimos ejercicios por este foro con algunas indicaciones o a veces con sus valiosas soluciones.

gracias.  


26-May-2012 01:52
Antonio P.G.

Hola,


En ese caso deberías de utilizar dos variables más:
       - Una que indique el valor de la letra anterior. (anterior)
       - Otra que acumule el valor del modificador a la variable. (moodificador).

Así podrías ir jugando con esas dos variables y las anteriores.

De todas maneras, hay otra estrategia, que se basa en que solo nos interesa el resultado final: ir sumando o restando según me encuentre un valor de signo, y luego corregir la variable.

Es decir, tengo:    ++c-.

Pues haría: 1, 1, 2, -1.

Es decir, lo único que hay que hacer es sumarle el "signo" (cuyo valor será (1 ó -1) a la variable "suma" y en la operación en la que se utilizaba la función ord(), restarle una unidad más a la variable. Copio, pego y modifico:

********************************************
signo = 1;
suma = 0;
for i:=1 to ord(cadena_texto[0]) do
    si cadena_texto[i] not in ('-','+') entonces
        suma:= suma + signo*(  ord(cadena_texto[i]) - 39  );
    else begin
        if cadena_texto[i] = '+' then
            signo = 1;
        else
            signo = -1;
        suma:= suma + signo;
    end;
*******************************************

Prueba así a ver si te funciona.

Nacho, ¿tú qué opinas?

Adiós.


27-May-2012 10:54
Nacho Cabanes (+30)

Veamos...

Veo algunas ideas que están bien, pero también otras "peligrosas". De momento, me voy a saltar el caso de expresiones con "--" y "++", para que la forma de analizar sea un poco más simple, de modo que (todavía) no funcionará con cosas como:

f--+c--+d-++e= 7

pero sí con expresiones sencillas como:

a+c-d+b

Un par de consideraciones:

- Para calcular el valor de cada variable a partir de la letra, la "a" (a minúscula) tiene el código ASCII 97, así que la expresión sería  "ord(letra)-96". Aun así, por legibilidad y por mantenibilidad, yo no pondría esa expresión directamente en los cálculos, sino que usaría una función auxiliar.

- En cuanto a las expresiones en sí, lo natural es hacerlo con "while": "mientras queden símbolos, leo el operador y la siguiente variable", añadiendo el caso excepcional de que si el segundo símbolo ha resultado ser también un operador, se trataría de un "++" o un "--". Si damos por sentado que (todavía) no existen estos dos símbolos, se podría leer incluso con un "for": se calcula cuantos "pares" hay, y se se van leyendo y calculando uno a uno.

- Esto sólo funciona si los operadores son + y -, que tienen la misma prioridad, de modo que se puede analizar de izquierda a derecha. Si hubiera *, /, potencias o símbolos de negación, que tienen distintas prioridades, el planteamiento debería ser totalmente distinto.

En un ratito os preparo un ejemplo completo...


27-May-2012 11:05
Nacho Cabanes (+30)

Allá va...

 
program analizarExpresiones1;
 
(* Calcula el valor de una variable; en este caso,
   será su posición en el alfabeto *)
function valorVariable(letra: char): integer;
begin
    valorVariable := ord(letra)-96;
end;
 
(* Analiza una expresión del tipo a+c-d+b *)
function analizar(expresion: string): integer;
var
    primeraVariable, operador, siguienteVariable: char;
    cantidadExpresiones: integer;
    posicion: integer;
    resultado: integer;
begin
    cantidadExpresiones := (length(expresion)-1) div 2;
 
    primeraVariable := expresion[1];
    resultado := valorVariable( primeraVariable );
    for posicion := 1 to cantidadExpresiones do
        begin
        operador := expresion[posicion*2];
        siguienteVariable := expresion[posicion*2+1];
 
        if operador = '+' then
            resultado := resultado + valorVariable( siguienteVariable )
        else if operador = '-' then
            resultado := resultado - valorVariable( siguienteVariable );
        (* else... mostrar mensaje de error *)
 
        end;
    analizar := resultado;
end;
 
(* Cuerpo del programa: casos de prueba *)
begin
    Write( analizar('a+c-d+b') );
end.
 
 

27-May-2012 15:11
oscar gomez

Cordial saludo profesor Nacho Cabanes, impecable tu explicacion y tu solucion mas clara, y facil de entender aun muchisimo mejor, mil gracias de verdad, sin dejar de serlo extensivo para Antonio, luis, fulanito etc....

profesor en el caso que comentamos con Antonio para expresiones:

f--+c--+d-++e= 7,

cual seria la estrategia a seguir o por lo menos la que tu propongas para hacer que cada variable segun sea que la anteceda o prrecedan operadores del tipo ++  y --, para aumentar ( o disminuir) en uno el valor de la variable antes de que sea usada la variable dentro de la expresion completa ( para casos en que el operador ++ anteceda a la variable), o en el caso de que  debe ser incrementado en uno despues de que su valor sea utilizado( para casos en que el operador ++ preceda a la variable), ojala puedas ayudarnos por que se que para mas de un compañero este ejercicio es de bastante enriquecimiento para no olvidar o dejar de practicar la programacion, en mi caso lo propuse por que me motiva muchisimo el aprender y APROVECHAR  de la mejor manera tus excelentes orientaciones y ayudas que nunca dejas de darnos y se que conmigo estaran todos los compañeros de acuerdo que son explicaciones de alto nivel y todo un privilegio al venir de un excelente profesor como tu... que afortunados sois quienes son tus alumnos.gracias por tu vocacion de brindaros siempre una mano y tenernos paciencia.
mil gracias y en espera ansiosa de tu conocimiento para de el al menos asimilar un poquito poco a poco.


30-May-2012 03:17
Luis Torres (+12)

Excelente explicación y maravillosa la manera de codificarlo. Todo se entiende con poco esfuerzo. Muy bien pensado, porque todo encaja. Me muero por ver la parte en la que aparecen los operadores ++ y --. Muchos saludos.






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)