Autor Tema: Analisis sintactico  (Leído 379 veces)

cris0710

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Analisis sintactico
« en: 17 de Marzo 2021, 20:18 »
Programa que lea una cadena de palabras separadas por espacios

Despues la va a escribir de nuevo, pero con la siguiente validación

Las palabras que sean un MES (ENERO, FEBRERO, MARZO)

   debe aparecer verde //EJEMPLO (En C++ pudiera ser *FEBRERO*)

las palabras que no sean un MES debe aparecer en rojo //EJEMPLO:  (En C++ pudiera ser /ZAPATO/)

SI fueron solo MESES (si no hay nada en rojo) y están en orden
    debe aparecer en azul ¡¡¡¡ !!!!

cris0710

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 17
    • Ver Perfil
Re: Analisis sintactico
« Respuesta #1 en: 17 de Marzo 2021, 20:55 »
Esto es lo que tengo hecho, estuve utilizando algunas partes del programa anterior que hicimos para la comparacion de meses

Código: [Seleccionar]
import java.util.*;// importa todas las librerias de utilidad para leer en teclado

public class AnalizadorSintactico {
 
  public static void main(String[] args) {
        Scanner scn = new Scanner(System.in);
        String cadena ="";
 
        while (!cadena.equals("salir")){
            if (!cadena.equals("salir")) {
                System.out.println("\n\t Ingresa la cadena de texto con el formato indicado");
                System.out.println("\t mes (espacio) mes.");
                System.out.println("\t Escriba \"salir\" para terminar programa");
                System.out.print("\n\t Cadena: ");
                cadena = scn.nextLine();
                String[] partes = cadena.split(" ");
               
                if (partes.length >1){
                   if (comprobarMes(partes[0])) {//if 1 comprobar el dia de la semana
                       
                    }// cierre if 1
                    else
                        System.out.println("\n \t"+partes[0] + " no es un mes.");
                }else //No hemos obtenido mas de 0 partes
                System.out.println("La cadena ingresada es incorrecta favor de verificar el formato \n");
            }
           
        }
       
        System.out.println("Fin de programa");
    }
     public static boolean comprobarMes(String mes) {
            boolean comprobacionSemana = false;
            if(mes.equals("enero") || mes.equals("febrero") || mes.equals("marzo") || mes.equals("abril") || mes.equals("junio")
                || mes.equals("julio") || mes.equals("agosto")|| mes.equals("septiembre")|| mes.equals("octubre")|| mes.equals("noviembre")|| mes.equals("diciembre"))
                return true;
            else
            return false;
    }
   
}


Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 702
    • Ver Perfil
Re: Analisis sintactico
« Respuesta #2 en: 18 de Marzo 2021, 02:32 »
Hola.

La verdad es que en esta ocasión va a ser un poco más difícil.
Primero, porque esta vez no sabemos el máximo de "partes" que vamos a tener que evaluar.
En el ejercicio anterior si lo sabíamos: dia, hora inicio y hora fin.
Eran tres partes, nos daba igual si el usuario metía una cadena de 500 partes, solo íbamos a preocuparnos de las 3 primeras.
Trabajábamos con partes[0], partes[1] y partes[2]... si habían más, no era asunto nuestro.

Pero esta vez no, si el usuario es un loco que mete 500 partes, vamos a tener que evaluarlas todas.
Así que el programa tiene que funcionar igual si meten 1 sola parte, 3, 15, 500, 80.000,... no hay límite de partes.
Por tanto habrá que usar bucle para recorrer todo el array de partes, mida lo que mida.

Otra cosa, averiguar si una parte es un mes o no, es sencillo.
Comprobar si TODAS las partes son meses, tampoco es problema.
Pero, comprobar si además son meses que están en el orden correcto...., esto ya son palabras mayores.

Vamos a tener que buscar una estrategia distinta. EL método que has puesto para comprobarMes() es correcto, pero vamos a necesitar algo más que eso.

Necesitamos tener algún tipo de lista con todos los meses y que estén ordenados.
Primero había pensado en usar un enum, que rara vez veo la ocasión de usar uno... pero al final he pensado que será más útil y versátil declarar un array con los 12 meses, en su orden correcto.
Código: [Seleccionar]
private static final String[] MESES = {"ENERO", "FEBRERO", "MARZO", "ABRIL", "MAYO", "JUNIO", "JULIO",
"AGOSTO", "SEPTIEMBRE", "OCTUBRE", "NOVIEMBRE", "DICIEMBRE"};

Con esto ya podemos ayudarnos, ya no solo para comprobar si una parte es un mes o no, si no también para comprobar si en el caso de tener varias partes, son meses ordenados.

Para comprobar si una parte (un String) es un mes, se podría seguir usando el mismo método que tu habías puesto.
Pero ya que vamos a tener este array a nuestra disposición, se puede simplificar de esta manera:
Código: [Seleccionar]
public static boolean comprobarMes(String mes) {
//Recorremos array de meses y comparamos con el mes recibido
for (String m: MESES)
if (m.equals(mes.toUpperCase())) //Si coincide con alguno de la lista...
return true; //...es que es un mes
//Si el bucle for no ha retornado true, es que no hemos recibido un mes válido
return false;
}

Con esto, ya podemos comprobar si una "parte" es un mes o no.

Pero lo difícil es comprobar si TODAS las "partes" corresponden a una secuencia de meses ordenada

Por ejemplo: febrero enero abril
TODOS son meses, pero no están en orden
En cambio: febrero marzo abril
TODOS son meses, y además SÍ están en orden.

Esto es lo que hay que comprobar.
Para ello he escrito un método, que puede ser un poco lioso, pero en realidad no lo es tanto.

Consta de dos secciones.
El método recibirá el array de "partes" al completo y primero comprobará si TODOS son meses.
Esto es sencillo, se recorre con un bucle y cada "parte" se analiza con comprobarMes().
Si alguno retorna FALSE, es que al menos una "parte" no es un mes, así que ya no hay nada más que comprobar, retornamos FALSE y se acabó.

Pero si todas las partes son TRUE, pues pasamos a la siguiente sección, sabemos que TODOS son meses, pero hay que ver si están en orden.
Esta es la parte que puede ser un poco confusa.

Para lograrlo lo que hago es coger el primer elemento del array partes y averiguar a que posición corresponde en el array de MESES.
Para esto, me apoyo en este otro método:
Código: [Seleccionar]
public static int posicionEnArray(String mes) {
for (int i = 0; i < MESES.length; i++)
if (MESES[i].equals(mes.toUpperCase()))
return i; //Devuelvo posición que ocupa en el array MESES

return -1; //En el improbable caso de que no sea un mes lo que evaluamos
}

Con esto consigo saber a que posición en MESES, equivale el primer mes que tengo en el array partes.
Y luego hago lo mismo con el último mes que tengo en partes.

Supongamos que partes es: marzo abril mayo junio

Tengo que "marzo" (partes[0]) equivale a "MARZO" (meses[2])
Y "junio" (partes[3]) equivale a "JUNIO" (MESES[5])

Tengo localizados el indice 2 como "inicio" y el indice 5 como "fin".
Bien, ahora lo primero que compruebo es que realmente "inicio" es menor que "fin", pues de lo contrario, es evidente que no están ordenados.

Y si "inicio" es menor que "fin", pues ahora lo que hago es recorrer de forma paralela los dos arrays.
El array partes lo recorro al completo desde el principio [ 0 ] hasta el final [3]
Pero MESES, solo recorro el rango entre "inicio" [2] y "fin" [5]

Y voy comparando un mes con otro, si coincide, aumento ambos índices y sigo recorriendo de formar paralela los siguientes meses.
Si alguno no coincide, es que no están ordenados, así que retorno FALSE.
Si llego al final del método sin que se haya retornado FALSE en ningún momento, es que todo está bien y tengo meses ordenados, pues retorno TRUE.

La explicación puede ser liosa, quizás viendo el código de este método se entienda mejor:
Código: [Seleccionar]
public static boolean soloMesesOrdenados(String[] partes) {

//Comprobamos si en las "partes" SOLO hay meses
for (String p: partes)
if (!comprobarMes(p))
return false; //Al menos uno, NO es un mes

/*
* Si el método todavía continua por aquí,
* es que TODOS son meses. Ahora hay que
* comprobar si están en orden.
* Para ello averiguamos que posición del array
* de MESES corresponde a nuestra primera "parte
* y a la última.
* Así sabemos que sección del array MESES hemos
* de buscar que coincida plenamente con
* el array de "partes"
*/
int inicio = posicionEnArray(partes[0]);
int fin = posicionEnArray(partes[partes.length-1]);
/*
* Tenemos el rango, pero antes de comparar
* hay que comprobar que inicio es menor que fin
* de lo contrario, es que no está ordenado
*/
if (inicio < fin) {
//Hay que usar distintos indices para cada array
int indiceMeses = inicio;
int indicePartes = 0;

while(indiceMeses <= fin) {
if (!MESES[indiceMeses].equals(partes[indicePartes].toUpperCase()))
return false; //Si no se cumple una comparación, es que no están en orden
else {
//Incrementamos indices para seguir comparando meses
indiceMeses++;
indicePartes++;
}
}
}
else
return false; //Inicio es mayor o igual a fin, imposible que esté ordenado

//Llegando aquí sin retornar false, es que las "partes" siguen el orden correcto de MESES
return true;
}

Bien, ya tenemos todos los métodos necesarios.
¿Cómo lo hacemos en el main?

Pues recogemos la cadena y separamos en partes con split(" ").

Si obtenemos un array de 0 elementos, indicamos que no se puede analizar la cadena, aunque en realidad esto no va a ocurrir nunca. Escriba lo que escriba el usuario, al menos un elemento siempre vamos a obtener.

Si el array solo tiene 1 elemento, entonces no es necesario comprobar si tenemos una lista ordenada de meses, solo hay que comprobar si ese elemento es un mes.

Si lo es, lo imprimimos en pantalla de color verde, si no, lo imprimimos en rojo.

Pero, si tenemos más de 1 elemento, entonces sí que lo primero es comprobar si tenemos una lista de solo meses bien ordenados.
Si es así, sacamos la cadena completa en color azul.

De lo contrario, pues con bucle, analizamos cada una de las partes del array que nos ha dado el split().
Los que sean meses los imprimimos en verde, lo que no en rojo.

Este es el código completo:
Código: [Seleccionar]
public class Meses {

private static final String[] MESES = {"ENERO", "FEBRERO", "MARZO", "ABRIL", "MAYO", "JUNIO", "JULIO",
"AGOSTO", "SEPTIEMBRE", "OCTUBRE", "NOVIEMBRE", "DICIEMBRE"};

public static void main(String[] args) {

Scanner scn = new Scanner(System.in);
String cadena ="";

while (!cadena.equals("salir")){

System.out.println("\n\n\t Ingresa la cadena de texto con el formato indicado");
System.out.println("\t mes (espacio) mes.");
System.out.println("\t Escriba \"salir\" para terminar programa");
System.out.print("\n\t Cadena: ");
cadena = scn.nextLine();

if (!cadena.equals("salir")) {

String[] partes = cadena.split(" ");

if (partes.length == 0)
System.out.println("\nNo se ha recibido una cadena analizable");
else if (partes.length == 1){
//Solo tenemos un supuesto mes
if (comprobarMes(partes[0]))
System.out.print("\033[32m" + partes[0] + "\u001B[0m");
else
System.out.print("\033[31m" + partes[0] + "\u001B[0m");
}
else {
//Tenemos varios supuestos meses
//Hay que comprobar si todos son meses y ordenados, para pintarlos de azul
if (soloMesesOrdenados(partes))
System.out.println("\033[34m" + cadena + "\u001B[0m");
else {
//No estan ordenados, incluso algunas partes quizás no sean meses
//Repasamos una a una para elegir color de salida
for (String parte: partes)
if (comprobarMes(parte))
System.out.print("\033[32m" + parte + " \u001B[0m");
else
System.out.print("\033[31m" + parte + " \u001B[0m");
}
}

}

}

System.out.println("Fin de programa");
scn.close();
}

public static boolean comprobarMes(String mes) {
//Recorremos array de meses y comparamos con el mes recibido
for (String m: MESES)
if (m.equals(mes.toUpperCase())) //Si coincide con alguno de la lista...
return true; //...es que es un mes
//Si el bucle for no ha retornado true, es que no hemos recibido un mes válido
return false;
}

public static int posicionEnArray(String mes) {
for (int i = 0; i < MESES.length; i++)
if (MESES[i].equals(mes.toUpperCase()))
return i; //Devuelvo posición que ocupa en el array MESES

return -1; //En el improbable caso de que no sea un mes lo que evaluamos
}

public static boolean soloMesesOrdenados(String[] partes) {

//Comprobamos si en las "partes" SOLO hay meses
for (String p: partes)
if (!comprobarMes(p))
return false; //Al menos uno, NO es un mes

/*
* Si el método todavía continua por aquí,
* es que TODOS son meses. Ahora hay que
* comprobar si están en orden.
* Para ello averiguamos que posición del array
* de MESES corresponde a nuestra primera "parte
* y a la última.
* Así sabemos que sección del array MESES hemos
* de buscar que coincida plenamente con
* el array de "partes"
*/
int inicio = posicionEnArray(partes[0]);
int fin = posicionEnArray(partes[partes.length-1]);
/*
* Tenemos el rango, pero antes de comparar
* hay que comprobar que inicio es menor que fin
* de lo contrario, es que no está ordenado
*/
if (inicio < fin) {
//Hay que usar distintos indices para cada array
int indiceMeses = inicio;
int indicePartes = 0;

while(indiceMeses <= fin) {
if (!MESES[indiceMeses].equals(partes[indicePartes].toUpperCase()))
return false; //Si no se cumple una comparación, es que no están en orden
else {
//Incrementamos indices para seguir comparando meses
indiceMeses++;
indicePartes++;
}
}
}
else
return false; //Inicio es mayor o igual a fin, imposible que esté ordenado

//Llegando aquí sin retornar false, es que las "partes" siguen el orden correcto de MESES
return true;
}

}

Y esto una prueba de la salida en consola:



Por último, sobre imprimir el texto en colores por consola
La consola de Java es limitada, sin embargo, se puede usar las secuencias de escape del standard ANSI para formatear en colores, tal y como hago en el código.

Esta secuencias funcionan sin problemas en la mayoría de IDE's y en las consolas de Linux y Macintosh (son primos hermanos, descendientes de UNIX)

Pero por ejemplo no funcionan, por defecto, en la consola del IDE Eclipse ni en la consola de Microsoft Windows.

En mi caso, uso Eclipse, y para que me funcione he tenido que instalar un plugin llamado "ANSI escape in console".

Para que funcione en la consola de Windows, en Windows anteriores había que cargar el ANSI.SYS al inicio.
En Windows 10 creo que eso ya no sirve y he leído algo sobre una librería llamada JANSI
Pero no lo he probado, no suelo usar la consola de Windows en Java.


Lo comento por si alguien se encuentra con que no le funciona lo de colorear el texto en consola. Se debe a esto, pero vamos, lo importante es comprender la lógica del programa.
Si luego salen bien o no los colores, es lo de menos.

Un saludo.
« Última modificación: 18 de Marzo 2021, 02:36 por Kabuto »
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".