El selector Case.
El poder de Case of en Pascal es muy grande, especialmente si se lo compara con cierto lenguaje. Por ejemplo permite rangos, valores separados por comas y una vez encontrada la coincidencia se sale del case, es decir, no se escribe un Break para finalizar cada sentencia.
Case trabaja con tipos de datos ordinales: enteros, enumerados, caracteres y cadenas. Los selectores deben ser todos del mismo tipo y literales (constantes) ya que se evalúan en tiempo de compilación.
Ejemplos:
const
num1=10;
var
num2:integer;
i:integer;
...
i:=20;
Case i of
num1 : writeLn('Es el número 10'); // Si i vale 10 se ejecuta esta sentencia y se sale del Case.
num2 : writeLn('Es un entero'); // Error
num1+10 : writeLn('Es el número 20');
else
writeLn('Es otro número');
writeLn('Pero no es el 10');
end;
Num2 es inválido porque no puede determinarse el valor de Num2 durante la compilación.
Num1 + 10 sí es válido ya que 10 + 10 = 20 es una expresión que se determina durante la compilación.
Else: también puede usarse Otherwise, es lo mismo, pero suele utilizarse Else. Nótese que no requiere begin .. end, no obstante se puede utilizar. Especificar Else no es obligatorio, si no encuentra el valor, simplemente se continúa con la siguiente sentencia del programa.
var
c:Char;
...
case c of
'a' : WriteLn('c es a');
'b' : WriteLn('c es a');
'c' : WriteLn('c es a');
'a' : WriteLn('c es a'); // Error
end;
Error: no se pueden duplicar los selectores, aunque es algo más que obvio.
var
s:String;
...
case s of
'azul', 'rojo' : WriteLn('Son colores');
'Debian', 'Linux Mint', 'Ubuntu' : WriteLn('Son sistemas operativos');
else
WriteLn('Es otra cosa.');
end;
Este ejemplo no tiene errores.
var
i,a:integer;
...
Case i of
0 : begin
WriteLn('El número es cero');
a:=i+1;
end;
1..99 : WriteLn('Es un número de 2 dígitos');
100, 101, 102..999 : WriteLn('Número de 3 dígitos');
else
WriteLn('Mayor o igual a 1000');
end;
Desde ya, se pueden usar rangos y como vemos, en un mismo selector se pueden especificar varios valores. No es obligatorio que los valores estén ordenados, pero es una buena práctica al tratarse de enteros, pues facilita la lectura del código.
Otro ejemplo con Char:
var
c:Char;
...
Case c of
'A..Z', 'a..z' : WriteLn('Es una letra');
'0..9' : WriteLn('Es un número');
1..2 : WriteLn('E'); //Error
else
WriteLn('No es ni letra ni número');
end;
Como vemos los rangos también se pueden utilizar con caracteres. El error se daría en 1..2 porque son enteros, no caracteres.
Para finalizar, un ejemplo con enumerados:
type
TDia=(Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo);
var
Dia:TDia;
...
Case Dia of
Lunes..Viernes : WriteLn('Es un día laborable');
Sabado : WriteLn('A veces los sábados se trabaja');
Domingo : WriteLn('Es feriado o no laborable');
end;
El siguiente código lo utilizo en el programa Marcadores:
type
TBuscar=(Duplicados,Errores,Error0,Error400,Error500,Redirect,OK200,Todos);
...
var
QueBuscar:TBuscar;
...
function TFSeleccionar.CargarGrid: Boolean;
var
i,f:Integer;
begin
f:=0;
for i:=Low(aReg) to High(aReg) do
begin
case QueBuscar of
Todos : begin
if ((aReg[i].chequear) and (not(aReg[i].Eliminar))) then
begin
Inc(f);
SGrid.InsertRowWithValues(f,['','','','']);
if aReg[i].borrar then SGrid.Cells[0,f]:='1' else SGrid.Cells[0,f]:='0';
SGrid.Cells[1,f]:=IntToStr(aReg[i].indice);
SGrid.Cells[2,f]:=aReg[i].URL;
SGrid.Cells[3,f]:=IntToStr(aReg[i].statuscode);
SGrid.Cells[4,f]:=IntToStr(aReg[i].Redirect);
SGrid.Cells[5,f]:=IntToStr(i);
end;
end;
Errores : begin
if ((aReg[i].chequear) and (not(aReg[i].Eliminar)) and ((aReg[i].statuscode=0) or (aReg[i].statuscode>=400))) then
begin
Inc(f);
SGrid.InsertRowWithValues(f,['','','','']);
if aReg[i].borrar then SGrid.Cells[0,f]:='1' else SGrid.Cells[0,f]:='0';
SGrid.Cells[1,f]:=IntToStr(aReg[i].indice);
SGrid.Cells[2,f]:=aReg[i].URL;
SGrid.Cells[3,f]:=IntToStr(aReg[i].statuscode);
SGrid.Cells[4,f]:=IntToStr(aReg[i].Redirect);
SGrid.Cells[5,f]:=IntToStr(i);
end;
end;
Duplicados : begin
if ((aReg[i].chequear) and (not(aReg[i].Eliminar))) then
begin
Inc(f);
SGrid.InsertRowWithValues(f,['','','','']);
SGrid.Cells[0,f]:='0';
SGrid.Cells[1,f]:=IntToStr(aReg[i].indice);
SGrid.Cells[2,f]:=aReg[i].URL;
SGrid.Cells[3,f]:=IntToStr(aReg[i].statuscode);
SGrid.Cells[4,f]:=IntToStr(aReg[i].Redirect);
SGrid.Cells[5,f]:=IntToStr(i);
end;
end;
end;
end;
Result:=SGrid.RowCount>0;
end;
martes, 19 de enero de 2021
El selector Case.
domingo, 17 de enero de 2021
Los procedimientos Break y Continue.
Break: sirve para salir de un bucle for, while o repeat y por ende solo deberá utilizarse únicamente dentro de estos bucles, caso contrario el compilador marcará el error. Actualmente, su uso, se considera una mala práctica de programación, al igual que, por ejemplo, while TRUE, sin embargo, podemos observar un hermoso ejemplar de while true en el código fuente del comando dd, pero usando el correspondiente break, desde ya.
Siempre hay debates respecto de su uso, pienso que no hay ninguna problema en emplear Break para salir de un bucle infinito siempre y cuando estemos 100% seguros de que se llegará al Break "a salvo". El hecho de evitar esta práctica utilizando un condicional tampoco garantiza que no se salga nunca del bucle. Si utilizamos while x<z do y x siempre es menor z estamos en la misma situación.
Por ejemplo, esto no termina nunca:
var
i:integer;
begin
while TRUE do
begin
Inc(i);
writeln(i);
end;
writeln('Fin.'); //Esta sentencia no se ejecutará nunca y el programa se colgará.
end;
En cambio
var
i:integer;
begin
i:=0;
while TRUE do
begin
Inc(i);
if i>100 then BREAK; // Se ejecuta la siguiente sentencia fuera del While do: writeln('Fin.');
writeln(i); // Cuando i llegue a valer 101 esta sentencia no se ejecutará.
end;
writeln('Fin.');
end;
finaliza cuando i vale 101. Claro que optaría por:
var
i:integer;
begin
i:=0;
while i<101 do
begin
Inc(i);
writeln(i);
end;
writeln('Fin.');
end;
mejor legibilidad y no utilizo while TRUE, que solo lo implementaría en casos muy especiales y en lo posible, nunca.
Continue: con este procedimiento se logra que se procese la siguiente iteración sin finalizar la actual, ignorando todas las sentencias posteriores a Continue (siempre dentro del bucle). Al igual que Break, solo debe utilizarse en bucles for to, while do y repeat until. A diferencia de Break, no hay ningún riesgo extra de bucle infinito, es decir, todo bucle while y repeat a veces tiene ese riesgo, no solo el while True do.
var
i:integer;
begin
for i:=1 to 100 do
begin
if (i mod 2) = 0 then CONTINUE;
writeln(i); // Cuando i es par esta sentencia no se ejecuta.
end;
writeln('Fin.');
end;
Debido a que no es muy habitual la utilización de estos procedimientos, opto por escribirlos en mayúscula para que destaquen.