Quando falei sobre máquina de estados nos artigos:
- Mini tutorial de Máquina de Estado (State Machine) - Parte 1
- Mini tutorial de Máquina de Estado (State Machine) - Parte 2
- Validando endereço de e-mail com máquina de estado
Falei que era muito útil no dia-a-dia para resolver problemas de lógica. Pois semana passada me deparei com um problema desses e pensei, isso é um caso de máquina de estados e saquei um papel e desenhei:
O que eu precisava, era de uma rotina que limitasse a largura de uma linha, mas existia algumas condições:
- o algorítimo deveria cortar a linha a partir de uma certa largura de caracteres;
- deveria desprezar (para contagem de largura) o que tivesse dentro de chaves {};
- deveria trazer uma excessão caso houvesse um colchete abrindo “[" antes da limitação de largura, mas que fosse fechado "]” apenas depois da largura.
Com estas premissas, montei o desenho anterior em um papel de rascunho. Fiz questão de escanear e mostrar o “garrancho”.
Nele podemos observar 3 estados (0, 1 e 2) e 2 métodos (Inclue e Inc). Diferente dos exemplos que mostrei anteriormente, aqui nesse desenho eu escrevi alguns códigos que só eu entendo, por se tratar de um rascunho. Para entendermos melhor, a legenda:
- <80 - Verdadeiro se a contagem é menor que a largura
- “{” - Verdadeiro se o próximo caracter for um “{” (equivalente: “}”, “[", "]“)
- <>”{” - Verdadeiro se o próximo caracter não for um “}” (equivalente: <>”]”)
- Inclue - Copia o caracter para a saída
- Inc - Incrementa contador de quantidade de caracteres para determinar a largura
- Erro - Excessão a ser levantada
Uma vez feito o desenho e testado mentalmente. O próximo passo foi escrever o seguinte código:
var
laco, qtdCaracteres, estado: Integer;
begin
qtdCaracteres := 0;
estado := 0;
Result := ”;
for laco := 1 to Length(ALinha) do
case estado of
0: begin
if ALinha[laco] = ‘{’ then
begin
estado := 1;
Result := Result + ALinha[laco];
end
else if (qtdCaracteres < FLarguraMaxima) and
(ALinha[laco] = ‘[') then
begin
estado := 2;
Inc(qtdCaracteres);
Result := Result + ALinha[laco];
end
else if qtdCaracteres < FLarguraMaxima then
begin
Inc(qtdCaracteres);
Result := Result + ALinha[laco];
end;
end;
1: begin
if ALinha[laco] = '}' then
estado := 0;
Result := Result + ALinha[laco];
end;
2: begin
if (qtdCaracteres < FLarguraMaxima) and
(ALinha[laco] = ']‘) then
begin
estado := 0;
Inc(qtdCaracteres);
Result := Result + ALinha[laco];
end
else if qtdCaracteres < FLarguraMaxima then
begin
Inc(qtdCaracteres);
Result := Result + ALinha[laco];
end
else
raise Exception.CreateFmt(
‘Esta linha excedeu a largura máxima (%d):’ +
#13#10‘%s’#13#10‘e um campo não apresenta o’ +
‘ seu fechamento "]".’ +
#13#10‘%s’#13#10‘Posicione o campo dentro do’ +
‘ limite de %0:d caracteres (parâmetro MAXWIDTH)’,
[FLarguraMaxima, ALinha, Result]);
end;
end;
end;
Esta é uma nested-function de um método de uma classe, o Field FLarguraMaxima é dado antes desta função ser chamada.
Muito show o rascunho. Mas confesso que o código ficou bem mais legivel que o rascunho hahahahaha.
abs
Então, o que eu escrevo no papel só eu consigo ler :-), faz tempo que é assim, as vezes, nem eu consigo ler :~(. A idéia do scan é justamente provar… Eu uso! Eu uso! Eu uso!