Diferencia entre revisiones de «Prog Estructuras de almacenamiento»

De MediaWiki
Ir a la navegación Ir a la búsqueda
Línea 272: Línea 272:
 
</syntaxhighlight>  
 
</syntaxhighlight>  
 
: El número de asteriscos en cada sección puede variar.
 
: El número de asteriscos en cada sección puede variar.
 +
: El número de espacios en blanco en cada sección puede variar.
 +
: En un futuro pueden aparecer nuevas secciones, por lo que no usaremos patrones buscando cadenas específicas.
 
: Siempre van a venir algún cliente y algún pedido.
 
: Siempre van a venir algún cliente y algún pedido.
 
: El teléfono siempre será de 9 dígitos.
 
: El teléfono siempre será de 9 dígitos.

Revisión del 10:45 18 mar 2018

Introducción

  • En lo que llevamos de curso ya hemos visto varias estructuras de almacenamiento: clases y arrays.
  • Para almacenar información no siempre llega guardar datos en tipo de datos simples, como un entero, una cadena, o un float.
Muchas veces es necesario guardar información de varios tipos o guardar un conjunto de datos del mismo tipo.
  • Vimos que podemos guardar información de diferentes tipos de datos formando 'un todo' en una clase. Por ejemplo, si quiero guardar la información de un empleado, con su nombre, edad, años de antigüedad...
Cuando definimos una clase indicamos con sus atributos (tipos de datos simples o compuestos) que información va a guardar.
Otras veces, la información que queremos guardar necesita una estructura de datos que permite guardar múltiples valores del mismo tipo, por ejemplo, un conjunto de notas de un alumno.
Esto ya vimos que lo podíamos guardar utilizando arrays.


  • Las estructuras de datos en base a diferentes criterios las podemos clasificar de varias formas.
  • En función de los diferentes tipos de datos que puedan guardar:
  • Que puedan guardar tipos de datos del mismo tipo. Ejemplo de este tipo de estructuras son las cadenas de caracteres (guardan múltiples caracteres), los arrays (ya vistos), las listas y los conjuntos.
  • Que puedan guardar tipos de datos diferentes. Por ejemplo las clases.
  • En función de si se puede modificar o no el número de elementos que conforman el array (su tamaño):
  • Que no se puedan modificar su tamaño una vez creada (estructuras estáticas). Por ejemplo, los arrays.
  • Que se pueda modificar su tamaño en tiempo de ejecución de forma dinámica (aumentar y disminuir de tamaño). Se conocen como estructuras dinámicas. Por ejemplo las listas, árboles, conjuntos y algunas clases que manejan caracteres.
  • En función de si los datos guardados en la estructura pueden estar ordenados:
  • Que no puedan estar ordenados. Por ejemplo los arrays. Debe ser el programador el que modifique los datos guardados para ordenarlos.
  • Que se puedan ordenar en base a diferentes criterios.



Cadena de caracteres

Existe otro método, el método compareTo. A diferencia del anterior, compara las dos cadenas lexicográficamente.
Disponemos de dos variantes en las que se ignora el hecho de que las letras estén en mayúsculas o en minúsculas:
  • Métodos usados habitualmente:

Strings dinámicos

  • Cada vez que usamos una cadena estamos creando un objeto de una clase String, cogiendo memoria. Esa memoria se reserva 'consecutivamente' y no puede variarse su tamaño, por lo que si queremos concatenar otra cadena, necesitamos utilizar otra zona de memoria donde quepa la cadena al completo.
Además las cadenas son 'inmutables' en el sentido que no podemos 'acortalas' o 'ampliarlas', ya que estaríamos creando una nueva cadena.
  • Por estos problemas, Java dispone de dos clases que permiten crear cadenas dinámicas, a las que vamos a poder ampliar o reducir su contenido.
  • StringBuilder.
  • StringBuffer: Esta es igual a la anterior pero está optimizada para ser usada por aplicaciones multihilo (multi-threads)
  • Dentro de la clase StringBuilder disponemos de los métodos:




Expresiones regulares

  • Para hacer uso de expresiones regulares necesitamos:
  • Verificar que la expresión regular es correcta. Para ello debemos hacer uso de la clase Pattern.
  • Verificar que la cadena cumple con la expresión regular. Para ello debemos hacer uso del método matcher de la misma clase, el cual devolverá un objeto de la clase Matcher que nos servirá para verificar si cumple la expresión regular llamando a su método matches().


  • Para compilar la expresión regular debemos hacer uso del método compile(String exp) de la clase Pattern.
En caso de que la expresión se incorrecta lanzará una excepción PatternSyntaxException.
Esta excepción es del tipo RunTimeException polo que no obliga a capturarla como ya vimos anteriormente en esta wiki.
Ejemplo:
1 Pattern patron = Pattern.compile("[abc]");
  • Una vez compilado ya podemos aplicarla sobre una cadena haciendo uso del método matcher'
Ejemplo:
1         Pattern patron = Pattern.compile("[abc]");
2         Matcher coincidencia = patron.matcher("a");
3         
4         if (coincidencia.matches()){
5             System.out.println("Patrón encontrado en la cadena");
6         }
7         else{
8             System.out.println("Patrón no encontrado en la cadena");
9         }


  • Métodos útiles de la clase Matcher:
  • matches(): En este caso la cadena no puede tener caracteres adicionales a los de la expresión regular.
  • lookingAt(): Busca el patrón al principio de la cadena y la cadena puede tener caracteres adicionales diferentes a los del patrón.
  • find(): Busca el patrón dentro de la cadena. Se utiliza en el caso de que haya el mismo patrón repetido varias veces en la cadena. Cada vez que se llame al métood find() buscará el siguiente patrón repetido. Por lo tanto la cadena puede contener caracteres adicionales a los del patrón a buscar.
Relacionado con find:
  • start(): Indica la posición inicial del patrón encontrado con find() en la cadena.
  • end(): Indica la posición final del patrón encontrado con find() en la cadena.
  • reset(): Hace que el find() vuelva a comenzar al principio de la cadena.


  • Indicar que en el método compile, en caso de necesitar indicar un carácter que pueda entrar en conflicto por su significado, debemos 'escaparlo' con '\'.
Así, si queremos buscar una expresión que contenga la barra (\) deberemos de poner: Pattern.compile("[abc]\\\\");
Si queremos buscar por \w (equivalente a [a-zA-Z_0-9]) deberemos poner: Pattern.compile("[abc]\\w");
  • En el método matcher, si queremos buscar la '\' deberemos poner: patron.matcher("\\\\casa");


  • Es posible formar grupos de combinaciones utilizando los paréntesis como por ejemplo: ([0-9]{2}@){2}
En este caso estamos buscando una cadena formada por dos números seguido del símbolo arroba repetido dos veces: 12@34@
Como vemos podemos aplicar al conjunto modificadores de repetición como los vistos anteriormente.
  • Otra utilidad de los conjuntos es que podemos 'acceder' a cada uno de ellos directamente.
Por ejemplo: ([a-z])([1-5]{3})([A-Z])
Tenemos tres conjuntos, el formado por la letra minúscula, el de los números y el de la letra mayúscula.
Después de hacer el matcher sobre esta expresión regular, por ejemplo: Matcher m = p.matcher("a123A" b444B");
Podemos acceder, después de realizar un find() (en este caso, ya que se repite varias veces en la cadena, deberíamos tener un while) podremos acceder a los valores de cada uno de los conjuntos de la forma: m.group(1), m.group(2) y m.group(3).



Ejercicios cadenas

Básicos

  • Indica cuantas instancias de clase String se crean en cada una de las instrucciones:
  • String cad = "Hola" + "Mundo";
  • String cad = new String("Hola Mundo");
  • String cad = new String("Hola Mundo") + ". Bienvenido" + new String(" a casa");
Lo mismo pasaría si usamos el método concat:
  • String cad = "Hola".concat("Mundo");
  • String cad = 10+5 + " no es igual " + 12+3;
¿ Cual es el resultado ?
  • Crea un objeto de cada una de las clases envoltorio de los tipos de datos numéricos primitivos (Integer, Float, Byte, Decimal) y imprímelos (sin necesidad de convertirlos) con el siguiente formato, haciendo uso:
  • Del método String.format
  • Del método printf:
Byte: ZZ
SHORT: GG
Integer: XX
Long: DDDDD
Float: YY.YY (dos dígitos para los decimales)
Double: DD.DDD (tres dígitos para los decimales)
Haz lo mismo pero concatenando (sin establecer formato) haciendo uso del símbolo más (+)


  • Explica como puede funcionar la siguiente instrucción:
byte num = 55;
String cad = "Juan tiene" + num;


  • Para convertir cadenas a números hacemos uso de los métodos parseXXXX de las clases envoltorio o bien llamando al método valueOf que devuelve una instancia de la clase envoltorio.
Pide gráficamente (JOptionPane.showInputDialog) que un usuario introduzca un número entero. Se debe informar al usuario (JOptionPane.showMessageDialog) si el número introducido no es correcto. En caso de que lo sea se mostrará el valor.
Deberá seguir solicitando introducir un número hasta que introduzca un número correcto entre 1 y 100.


  • Implementa un ejemplo de cada uno de los métodos utilizados habitualmente con la clase String.


  • Indica la salida de las siguientes órdenes:
1         String cad = "Casa".concat("Angel").replace("a", "o");
2         String cad = "Juan".length() + "Pedro".substring("ejemplo".indexOf("e"),2);
3         boolean salida = "Pase y diga una frase".replace("ase","to").endsWith("ta");
4         int comparar = "Amigo".compareToIgnoreCase("amiga");  (indicar si el número 'comparar' es positivo o negativo o cero.
5         int pos = "Abracadabra".replace("ra","le").lastIndexOf("bl");



Strings dinámicos

  • Haz uso de la clase StringBuilder para a partir de una cadena obtener otra utilizando los métodos disponibles para borrar, reemplazar, insertar y añadir (primero hazlo con varias órdenes y después con una sola. Debes de hacer uso de los tres métodos):
  • Tenemos: "La casa de la pradera" => "El coso mío de praderaaaa"


  • Utiliza la clase StringBuilder (y sólo ella) para hacer que el último carácter de la cadena pase a la primera posición posición.
Haz una modificación y crea un método al que se le pase como parámetro el número de posiciones a rotar y una cadena y devuelva la cadena rotada el número de veces indicado en el parámetro.


Expresiones regulares

  • Busca la expresión regular (y compruébala en este enlace) que cumpla lo siguiente:
  • Una entrada de 5 a 10 números entre 3 y 7 seguidos por la letra a o A.
  • Una entrada con vocales hasta un máximo de 10 seguido opcionalmente de un número.
  • Una entrada con el siguiente patrón: XX00000ZZ0 siendo XX letras entra la a y la z, ZZ vocales, 00000 números entre 0 y 5 y 0 números entre 0 y 9 y que pueden repetirse indefinidamente
  • Una entrada de 5 a 10 letras seguidos por la letra a o b de forma opcional (pueden aparecer o no)


  • Una entrada que debe comenzar y acabar con un número y pueda llevar cualquier carácter entre los dos números.
  • Dada la siguiente expresión regular: ^[0-9]{2,}[^a-g]?[0-9]*.{2}$ indica cuales de las siguientes cadenas cumplirían dicha expresión utilizando el método find y el método lookingAt
  • 12q1qq
  • 2q111w
  • 11q11casa
  • p11axxs543323
Compruébalo en regexr.com.
  • Una expresión que valide un correo electrónico, partiendo que el dominio tendrá el formato: galicia.xx o galicia.xxx



  • Crea una expresión regular que responda a este patrón:
  • Almohadilla seguido de 5 números, seguido de almohadilla, repitiendo esta misma combinación de dos a cuatro veces.
  • Un código postal está formado por dos dígitos para la provincia seguido del número postal formado por tres números. Crea un programa que utilizando expresiones regulares analice una cadena de texto en la que van a venir múltiples códigos postales separados por espacio (puede venir un código postal solo). Tendrá que analizar completamente dicha cadena y mostrar el código de provincia y número de cada uno de ellos.


  • Pide gráficamente al usuario una entrada para que introduzca su NIF o NIF extranjero (lleva una letra al comienzo y al final). Deberás informar si el dato introducido es correcto.
El formato que quieres que se cumpla es el de una letra inicial opcional, un número de entre cinco y ocho dígitos y una letra final. La letra se podrá introducir en mayúsculas o minúsculas, pero se guardará (en una variable) todo con letras mayúsculas.
Debes asegurarte que el usuario no introduce más caracteres que los indicados.


  • Crea un JFrame con un textarea y un botón buscar.
Al pulsar el botón deberás buscar en el contenido del textarea cuantas veces aparece el patrón: un carácter cualquiera, seguido de 2 números con valores entre uno y seis cada uno y seis letras (mayúsculas o minúsculas).
Informarás al usuario de cuantas veces ha aparecido el patrón.


  • Dado el siguiente contenido de un archivo de texto:
**  CLIENTES   **
* CLIENTE *
Nombre: Juan
Dirección: C/ AAAA
Tfno: 999999999
*** PEDIDOS ***
{Codigo - Cantidad}
{C1 - 10}
{E2 - 5}
* FIN PEDIDOS *
** FIN CLIENTE **
* CLIENTE *
Nombre: Pedro
Dirección: C/ BBBB
Tfno: 111111111
*** PEDIDOS ***
{Codigo - Cantidad}
{W22221 - 20}
{E22112 - 15}
* FIN PEDIDOS *
** FIN CLIENTE **
** FIN CLIENTES   **
El número de asteriscos en cada sección puede variar.
El número de espacios en blanco en cada sección puede variar.
En un futuro pueden aparecer nuevas secciones, por lo que no usaremos patrones buscando cadenas específicas.
Siempre van a venir algún cliente y algún pedido.
El teléfono siempre será de 9 dígitos.
El código de pedido siempre será una letra mayúscula seguida de dígitos.
La cantidad siempre será mayor que cero.
Lee el siguiente archivo línea a línea comprobando que cumple alguna de las expresiones regulares.
Deberás crear expresiones regulares.
  • Una que englobe a los principio / fin de todas las secciones.
  • Otra para cada una de las líneas de información del cliente.
  • Otra para cada línea de pedido.
Deberás mostrar por pantalla cada una de las secciones con los datos de los clientes y los pedidos.

Solución ejercicios cadena

Básicos

  • Indica cuantas instancias de clase String se crean en cada una de las instrucciones:
  • String cad = "Hola" + "Mundo"; => 3.
  • String cad = new String("Hola Mundo"); => 2.
  • String cad = new String("Hola Mundo") + " Bienvenido" + new String(" a casa"); => 7.
Lo mismo pasaría si usamos el método concat:
  • String cad = "Hola".concat("Mundo"); => 3.
  • String cad = 10+5 + " no es igual a " + 12+3; => 5
Resultado: 15 no es igual a 123


  • Crea un objeto de cada una de las clases envoltorio de los tipos de datos numéricos primitivos (Integer, Float, Byte, Decimal) y imprímelos (sin necesidad de convertirlos) con el siguiente formato, haciendo uso del método printf:

Byte: ZZ SHORT: GG Integer: XX Long: DDDDD Float: YY.YY (dos dígitos para los decimales) Double: DD.DDD (tres dígitos para los decimales)

1         Byte b = 2;
2         Short s = 2131;
3         Integer i = 34;
4         Long l = 324324l;
5         Float f = 12.45f;
6         Double d = 44.24d;
7         
8         System.out.printf("\nByte:%d\nShort:%d\nInteger:%d\nLong:%d\nFloat:%.2f\nDouble:%.3f",b,s,i,l,f,d);
En este caso estamos haciendo uso de objetos de clases y cuando se imprimen se llama al método toString de la clase.
Haz lo mismo pero concatenando (sin establecer formato).
Al igual que en el caso anterior está llamando al método toString.


  • Explica como puede funcionar la siguiente instrucción:
byte num = 55;
String cad = "Juan tiene" + num;
En este caso, Java convierte el tipo de dato primitivo (byte) a la clase envoltorio Byte y después llama al método toString de la misma.


  • Indica la salida de las siguientes órdenes:
1         String cad = "Casa".concat("Angel").replace("a", "o");                                 => CosoAngel
2         String cad = "Juan".length() + "Pedro".substring("ejemplo".indexOf("e"),2);            => 4Pe
3         boolean salida = "Pase y diga una frase".replace("ase","to").endsWith("ta");           => false
4         int comparar = "Amigo".compareToIgnoreCase("amiga");                                   => Positivo 
5         int pos = "Abracadabra".replace("ra","le").lastIndexOf("bl");                          => 8



Strings dinámicos

  • Haz uso de la clase StringBuilder para a partir de una cadena obtener otra utilizando los métodos disponibles para borrar, reemplazar, insertar y añadir (primero hazlo con varias órdenes y después con una sola. Debes de hacer uso de los tres métodos):
  • Tenemos: "La casa de la pradera" => "El coso mío de praderaaaa"
1         StringBuilder cadena = new StringBuilder("La casa de la pradera");
2         cadena.replace(cadena.indexOf("La"), 2, "El");
3         cadena.replace(cadena.indexOf("casa"), 7, "coso");
4         cadena.insert(8,"mío ");
5         cadena.delete(14, 17);
6         cadena.append("aaa");


  • Utiliza la clase StringBuilder (y sólo ella) para hacer que el último carácter de la cadena pase a la primera posición posición.
Haz una modificación y crea un método al que se le pase como parámetro el número de posiciones a rotar y una cadena y devuelva la cadena rotada el número de veces indicado en el parámetro.
1        StringBuilder sb = new StringBuilder("Cadena de ejemplo");
2        sb.insert(0, sb.charAt(sb.length()-1));
3        sb.deleteCharAt(sb.length()-1);
4        System.out.println(sb);
Método rotarCadena:
 1     public static String rotarCadena(String cadena, int numRotar) {
 2         
 3         StringBuilder sb = new StringBuilder(cadena);
 4         
 5         for (int cont=0;cont <numRotar;cont++){
 6             sb.insert(0, sb.charAt(sb.length()-1));
 7             sb.deleteCharAt(sb.length()-1);
 8         }
 9         
10         return sb.toString();
11     }



Expresiones regulares

  • Busca la expresión regular (y compruébala en este enlace) que cumpla lo siguiente:
  • Una entrada de 5 a 10 números entre 3 y 7 seguidos por la letra a o A. => [3-7]{5,10}[aA]
  • Una entrada con vocales hasta un máximo de 10 seguido opcionalmente de un número. => [a-zA-Z]{1,10}[0-9]
  • Una entrada con el siguiente patrón: XX00000ZZ0 siendo XX letras entra la a y la z, ZZ vocales, 00000 números entre 0 y 5 y 0 números entre 0 y 9 y que pueden repetirse indefinidamente => [a-z]{2}[0-5]{5}[aeiou]{2}[0-9]+
  • Una entrada de 5 a 10 letras seguidos por la letra a o b de forma opcional (pueden aparecer o no) => [a-z]{5-10}[ab]?


  • Una entrada que cumpla: Debe comenzar y acabar con un número y puede llevar cualquier carácter entre los dos números => ^[0-9].+[0-9]$
  • Una expresión que valide un correo electrónico, partiendo que el dominio tendrá el formato: galicia.xx o galicia.xxx => ^\w+@galicia\.[a-zA-Z]{2,3}$
Nota: Fijarse que en el caso de utilizar el método match no hace falta poner ^ y $ en la expresión.
Debemos escapar el punto ya que sino lo interpretará como 'cualquier carácter'.


  • Crea una expresión regular que responda a este patrón:
  • Almohadilla seguido de 5 números, seguido de almohadilla, repitiendo esta misma combinación de dos a cuatro veces => ^(#[0-9]{5}#){2,4}$
Nota: Fijarse que en el caso de utilizar el método match no hace falta poner ^ y $ en la expresión.
  • Un código postal está formado por dos dígitos para la provincia seguido del número postal formado por tres números. Crea un programa que utilizando expresiones regulares analice una cadena de texto en la que van a venir múltiples códigos postales separados por espacio (puede venir un código postal solo). Tendrá que analizar completamente dicha cadena y mostrar el código de provincia y número de cada uno de ellos.
1         Pattern patron = Pattern.compile("([0-9]{2})([0-9]{3})");
2         Matcher coincidencia = patron.matcher("12111 aaaa 13444");
3         
4         while (coincidencia.find()){
5             System.out.println("Provincia: " + coincidencia.group(1));
6             System.out.println("Número: " + coincidencia.group(2));
7             
8         }




-- Ángel D. Fernández González -- (2017).