Máquina de Estados - Provando a praticidade

Quando falei sobre máquina de estados nos artigos:

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:

maquina_estado_4

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:

function LimitaLargura(const ALinha: string): string;
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.

2 Respostas para “Máquina de Estados - Provando a praticidade”


  1. 1 Douglas Cunha

    Muito show o rascunho. Mas confesso que o código ficou bem mais legivel que o rascunho hahahahaha.
    abs

  2. 2 Alecão

    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!

Deixe uma Resposta