Vamos a ver algún otro tipo de datos, quizá menos utilizado que los anteriores, pero que ayudan a que nuestros programas sean más elegantes y más legibles.
Podemos indicar los posibles valores que puede tomar una variable, indicándolo en forma de subrango, al igual que se hace con los índices de un array:
var
dia: 1..31;
Un ejemplo completo podría ser así:
(* SUBRANGO1.PAS, Variables de tipo "subrango" *)
(* Parte de CUPAS5, por Nacho Cabanes *)
program SubRango1;
var
dia: 1..31;
begin
write('Introduce el dia: ');
readLn(dia);
writeLn('Has tecleado ', dia);
end.
(*
Ejemplo de ejecucion 1:
Introduce el dia: 12
Has tecleado 12
Ejemplo de ejecucion 2:
Introduce el dia: 45
Has tecleado 45
*)
Pero hay que tener una precaución: estas construcciones hacen nuestro programa más legible, pero es frecuente que el compilador no haga comprobaciones para asegurarse de que los valores realmente deban estar en ese rango, de modo que se nos permitirá introducir valores mayores o menores, como se ve en ese ejemplo.
Como alternativa, en algunos compiladores podemos forzar que se comprueben errores de valores fuera de rango en tiempo de ejecución, de modo que el programa se interrumpiría con un código de error (que más adelante veremos cómo interceptar) si ese valor introducido no es correcto. En Turbo Pascal y Free Pascal, esto se consigue incluyendo en nuestro programa la directiva {$R+}, así:
(* SUBRANGO2.PAS, Variables de tipo "subrango" *)
(* Version con comprobacion de rangos *)
(* Parte de CUPAS5, por Nacho Cabanes *)
{$R+}
program SubRango2;
var
dia: 1..31;
begin
write('Introduce el dia: ');
readLn(dia);
writeLn('Has tecleado ', dia);
end.
(* Ejemplo de ejecucion:
Introduce el dia: 45
Runtime error 201 at $080480FB
$080480FB
$08063733
*)
Ejercicio propuesto 4.4.1.1: Crea un programa que pida un dato del 1 al 12 y muestre el nombre del mes correspondiente. El dato debe ser de tipo subrango, y los nombres deben estar guardados en un array de strings.
Ejercicio propuesto 4.4.1.2: Usando subrangos, crea un programa que pida una hora (de 0 a 24), unos minutos (de 0 a 60) y unos segundos (de 0 a 60) y calcule cuántos segundos han pasado desde la medianoche.
Podemos crear nuestros propios tipos de datos enumerados, detallando todos los valores que puede tomar una variable, así:
var dia: (Lunes, Martes, Miercoles, Jueves, Viernes,
Sabado, Domingo);
Podemos asignar uno de esos valores a la variable (sin comillas, porque no son cadenas de texto), comprobar un valor, o incluso avanzar de un valor al siguiente con "succ" (sucesor) y retroceder al que le precede con "prec" (precedente):
(* ENUMERADO1.PAS, Variables enumeradas *)
(* Parte de CUPAS5, por Nacho Cabanes *)
program Enumerado1;
var
dia: (Lunes, Martes, Miercoles, Jueves, Viernes,
Sabado, Domingo);
begin
dia := Lunes;
if (dia = Martes) then
writeLn('El dia es Martes')
else
writeLn('No es Martes');
dia := succ( dia );
if (dia = Martes) then
writeLn('Ahora el dia es Martes')
else
writeLn('Aun no es Martes')
end.
(* Resultado:
No es Martes
Ahora el dia es Martes
*)
También se puede saber el "número de orden", con la función "ord". Por ejemplo, "ord(Lunes)" valdría 1, porque es el primer dato de la lista. De igual modo, podríamos recorrer todos los valores posibles usando "for": "for dia := Lunes to Viernes do ..."
En algunos compiladores, como Free Pascal (pero no Turbo Pascal, ni siquiera en su versión 7), se nos permite mostrar en pantalla el valor de un dato enumerado, y habitualmente lo que ocurrirá es que se mostrará la cadena de texto equivalente, como en este ejemplo:
(* ENUMERADO2.PAS, Variables enumeradas *)
(* Visualizacion (solo Free Pascal) *)
(* Parte de CUPAS5, por Nacho Cabanes *)
program Enumerado2;
var
dia: (Lunes, Martes, Miercoles, Jueves, Viernes,
Sabado, Domingo);
begin
dia := Lunes;
if (dia = Lunes) then
writeLn('El dia es ', dia);
dia := succ( dia ); { Avanzamos un dia }
writeLn('Ahora el dia es ', dia);
end.
(* Resultado:
El dia es Lunes
Ahora el dia es Martes
*)
Pero Free Pascal llega más allá, nos permite incluso introducir valores mediante teclado para una variable enumerada (nuevamente, esta posibilidad no existe en Turbo Pascal):
(* ENUMERADO3.PAS, Variables enumeradas *)
(* Lectura desde teclado (Free Pascal) *)
(* Parte de CUPAS5, por Nacho Cabanes *)
program Enumerado3;
var
dia1, dia2: (Lunes, Martes, Miercoles, Jueves, Viernes,
Sabado, Domingo);
begin
dia1 := Lunes;
writeLn('Introduce un dia: ');
readLn(dia2);
if (dia1 = dia2) then
writeLn('El dia es ', dia1)
else
begin
writeLn('Mi dia es ', dia1);
writeLn('Y el tuyo es ', dia2);
end;
end.
(*
Ejemplo de ejecucion 1:
Introduce un dia:
lunes
El dia es Lunes
Ejemplo de ejecucion 2:
Introduce un dia:
martes
Mi dia es Lunes
Y el tuyo es Martes
*)
En compiladores más antiguos, deberemos usar otros tipos de datos (números, caracteres o cadenas de texto) para interactuar con el usuario, y convertirlos posteriormente al tipo enumerado dentro de nuestro programa, empleando "if" o "case".
Ejercicio propuesto 4.4.2.1: Crea un programa que permita al usuario sumar, restar, multiplicar o dividir dos números. Debe introducir un primer número, luego el segundo número y finalmente escoger la operación. Las posibles operaciones deben estar enumeradas. Debe funcionar en cualquier versión de Pascal, no sólo en Free Pascal.
Ejercicio propuesto 4.4.2.2: Si usas Free Pascal, crea un tipo enumerado que contenga los nombres de los meses, y muestra sus valores usando "for".
También podemos crear y manipular conjuntos (sets). Un conjunto está formado por una serie de elementos de un tipo base, que debe ser un ordinal de no más de 256 valores posibles, como un "char", un "byte" o un enumerado.
Para construir un "set" utilizaremos los corchetes ( [ ] ), y dentro de ellos enumeramos los valores posibles, uno a uno, o bien como rangos de valores separados por ".." :
var
letras: set of char;
begin
letras := ['a', 'b', 'c', 'd'];
(* ... *)
end.
Las operaciones que podemos realizar con conjuntos son:
Operac | Nombre |
+ | Unión |
- | Diferencia |
* | Intersección |
in | Pertenencia |
Así, un ejemplo que cree un conjunto a partir de dos subconjuntos y que compruebe si un cierto dato pertenece o no al conjunto, podría quedar así:
(* SET01.PAS, Ejemplo de conjuntos (Sets) *)
(* Parte de CUPAS5, por Nacho Cabanes *)
program Set01;
var
minusculasValidas,
mayusculasValidas,
letrasValidas: set of char;
letra: char;
begin
minusculasValidas := ['a', 'b', 'c', 'd'];
mayusculasValidas := ['F', 'H', 'K', 'M'];
letrasValidas := minusculasValidas
+ mayusculasValidas;
repeat
writeLn( 'Introduce una letra...' );
readLn( letra );
if not (letra in letrasValidas) then
writeLn('No aceptada!');
until letra in letrasValidas;
end.
(* Ejemplo de ejecucion:
Introduce una letra...
e
No aceptada!
Introduce una letra...
t
No aceptada!
Introduce una letra...
n
No aceptada!
Introduce una letra...
m
No aceptada!
Introduce una letra...
M
*)
Ejercicio propuesto 4.4.3.1: Crea un programa que pida al usuario que pulse "s" o "n" y no le deje seguir hasta que escoja una de esas dos opciones. Usa un conjunto para los datos aceptables y el operador "in" para ver si lo que ha tecleado el usuario es uno de esos datos aceptables.
Ejercicio propuesto 4.4.3.2: Crea un programa que muestre un menú y permita al usuario introducir letras en un conjunto (usando la operación "unión"), eliminarlas (usando la "diferencia") o ver si una cierta letra aparece en en el conjunto (con "in").