Como fazer comparação de campo em delphi

Neste post vou ensinar como utilizar campos calculados no Delphi. Mais um recurso muito interessante, que facilita muito nossas vidas em alguns casos específicos.

Como o próprio nome sugere, são campos calculados em memória quando se está executando o seu projeto.

COMO UTILIZAR CAMPOS CALCULADOS NO DELPHI

Esses tipos de campos são muito úteis quando precisamos criar uma coluna temporária em tempo de execução para nos fornecer alguma determinada informação de forma rápida e prática.

Podemos fazer desde operações aritméticas até concatenação de strings. Você pode fazer qualquer tipo de rotina com campos calculados. Só tem que ter cuidado para não comprometer o desempenho do seu sistema.

Qualquer componente da classe TDataSet suporta campos calculados. Neste exemplo vou utilizar o ClientDataSet da paleta Data Access.

Eu considero o ClientDataSet um dos melhores e mais versáteis componentes do Delphi. E diferente dos outros DataSets, ele nos fornece uma opção a mais, que é a criação de campos calculados mas do tipo InternalCalc.

Resumindo, podemos criar dois tipos de campos calculados utilizando o ClientDataSet no Delphi: Calculated InternalCalc.

Calculated x InternalCalc

Calculated

Esses campos são calculados a todo momento pelo seu sistema. A cada mudança de registro por exemplo, o evento OnCalcFields é disparado e o seu bloco de instruções será executado.

Além disso o seu valor não é armazenado em memória, eles apenas são exibidos como resultado para visualização e manipulação.

InternalCalc

Esses campos também são calculados pelo evento OnCalcFields do ClientDataSet. Porém, os valores deste tipo de campo são armazenados internamente na memória do ClientDataSet.

Isso nos dá uma série de possibilidades. Por exemplo, podemos indexar estes campos, ou, utilizar campos agregados para fazer operações aritméticas no seu valor. Já o campo calculado do tipo Calculated, não nos dá essa opção.

Além disso, o estado dsInternalCalc do ClientDataSet é disparado bem menos vezes em comparação ao estado dsCalcFields. Por isso, utilizar o tipo InternalCalc se torna um atrativo a mais.

Veja no vídeo a seguir: Como Utilizar Campos Calculados no Delphi.

Download do Exemplo Utilizado no Vídeo

Dúvidas? Deixe seu comentário abaixo.

Para um correto entendimento sobre o problema é recomendável ler sobre
longest common subsequence (LCS) problem na Wikipedia.

Depois de ler o artigo da Wikipedia sobre, Yanniel obteve uma visão geral do problema e decidiu implementar uma classe Delphi para fazer o truque de comparação de strings, que é a base para a comparação de arquivos de texto.

No exemplo temos duas strings para serem comparadas, onde vamos destacar em azul os caracteres adicionados à primeira string e em vermelho os caracteres removidos dela. Os caracteres comuns (inalterados) manterão a cor padrão.

Como fazer comparação de campo em delphi

A classe de comparação irá parecer com isso:

1 2 3 4 5 6 7 8 9 10 11 type TDiff = record Character: Char; CharStatus: Char; //Possible values: [+, -, =] end;   TStringComparer = class …………… public class function Compare(aString1, aString2: string): TList<TDiff>; end;

type TDiff = record Character: Char; CharStatus: Char; //Possible values: [+, -, =] end; TStringComparer = class …………… public class function Compare(aString1, aString2: string): TList<TDiff>; end;

Quando você chama TStringComparer.Compare, uma lista genérica de registros TDiff é criada. Um registro TDiff contém um caractere e se esse caractere foi adicionado ( CharStatus = ‘+’), removido ( CharStatus = ‘-‘) ou inalterado ( CharStatus = ‘=’) em ambas as sequências sob comparação.

Vamos colocar duas edits ( Edit1 , Edit2 ), uma edição rica ( RichEdit1 ) e um botão ( Button1 ) em um formulário Delphi. Para destacar as diferenças, coloque o seguinte código no evento OnClick do botão:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 procedure TForm1.Button1Click(Sender: TObject); var Differences: TList<TDiff>; Diff: TDiff; begin //Yes, I know...this method could be refactored ;-) Differences:= TStringComparer.Compare(Edit1.Text, Edit2.Text); try RichEdit1.Clear; RichEdit1.SelStart:= RichEdit1.GetTextLen; for Diff in Differences do if Diff.CharStatus = '+' then begin RichEdit1.SelAttributes.Color:= clBlue; RichEdit1.SelText := Diff.Character; end else if Diff.CharStatus = '-' then begin RichEdit1.SelAttributes.Color:= clRed; RichEdit1.SelText:= Diff.Character; end else begin RichEdit1.SelAttributes.Color:= clDefault; RichEdit1.SelText:= Diff.Character; end; finally Differences.Free; end; end;

procedure TForm1.Button1Click(Sender: TObject); var Differences: TList<TDiff>; Diff: TDiff; begin //Yes, I know...this method could be refactored ;-) Differences:= TStringComparer.Compare(Edit1.Text, Edit2.Text); try RichEdit1.Clear; RichEdit1.SelStart:= RichEdit1.GetTextLen; for Diff in Differences do if Diff.CharStatus = '+' then begin RichEdit1.SelAttributes.Color:= clBlue; RichEdit1.SelText := Diff.Character; end else if Diff.CharStatus = '-' then begin RichEdit1.SelAttributes.Color:= clRed; RichEdit1.SelText:= Diff.Character; end else begin RichEdit1.SelAttributes.Color:= clDefault; RichEdit1.SelText:= Diff.Character; end; finally Differences.Free; end; end;

O programa irá fazer parecido com a imagem abaixo:

Como fazer comparação de campo em delphi

Abaixo segue um exemplo de implementação, lógico que diversas melhorias podem ser implementadas.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 unit StringComparison;   interface   uses Math, Generics.Collections;   type TDiff = record Character: Char; CharStatus: Char; //Possible values: [+, -, =] end;   TStringComparer = class strict private type TIntArray = array of array of Integer; class function LCSMatrix(X, Y: string): TIntArray; class procedure ComputeDifferences(aLCSMatrix: TIntArray; X, Y: string; i, j: Integer; aDifferences: TList<TDiff>); public class function Compare(aString1, aString2: string): TList<TDiff>; end;   implementation   { TStringComparer }   class function TStringComparer.LCSMatrix(X, Y: string): TIntArray; var m, n, i, j: Integer; begin m:= Length(X); n:= Length(Y);   //We need one extra column and one extra row to be filled with zeroes SetLength(Result, m + 1, n + 1);   //First column filled with zeros for i := 0 to m do Result[i, 0] := 0;   //First row filled with zeros for j:= 0 to n do Result[0, j]:= 0;   //Storing the lengths of the longest common subsequences //between prefixes of X and Y for i:= 1 to m do for j:= 1 to n do if X[i] = Y[j] then Result[i, j] := Result[i-1, j-1] + 1 else Result[i, j]:= Max(Result[i, j-1], Result[i-1, j]); end;   class procedure TStringComparer.ComputeDifferences(aLCSMatrix: TIntArray; X, Y: string; i, j: Integer; aDifferences: TList<TDiff>); var CharDiff: TDiff; begin if (i > 0) and (j > 0) and (X[i] = Y[j]) then begin ComputeDifferences(aLCSMatrix, X, Y, i-1, j-1, aDifferences); CharDiff.Character:= X[i]; CharDiff.CharStatus:= '='; //The character did not change aDifferences.Add(CharDiff); end else if (j > 0) and ((i = 0) or (aLCSMatrix[i,j-1] >= aLCSMatrix[i-1,j])) then begin ComputeDifferences(aLCSMatrix, X, Y, i, j-1, aDifferences); CharDiff.Character:= Y[j]; CharDiff.CharStatus:= '+'; //The character was added aDifferences.Add(CharDiff); end else if (i > 0) and ((j = 0) or (aLCSMatrix[i,j-1] < aLCSMatrix[i-1,j])) then begin ComputeDifferences(aLCSMatrix, X, Y, i-1, j, aDifferences); CharDiff.Character:= X[i]; CharDiff.CharStatus:= '-'; //The character was removed aDifferences.Add(CharDiff); end; end;   //This is a factory method class function TStringComparer.Compare(aString1, aString2: string): TList<TDiff>; var Matrix: TIntArray; begin Result:= TList<TDiff>.Create; Matrix:= LCSMatrix(aString1, aString2); ComputeDifferences(Matrix, aString1, aString2, Length(aString1), Length(aString2), Result); end;   end.

unit StringComparison; interface uses Math, Generics.Collections; type TDiff = record Character: Char; CharStatus: Char; //Possible values: [+, -, =] end; TStringComparer = class strict private type TIntArray = array of array of Integer; class function LCSMatrix(X, Y: string): TIntArray; class procedure ComputeDifferences(aLCSMatrix: TIntArray; X, Y: string; i, j: Integer; aDifferences: TList<TDiff>); public class function Compare(aString1, aString2: string): TList<TDiff>; end; implementation { TStringComparer } class function TStringComparer.LCSMatrix(X, Y: string): TIntArray; var m, n, i, j: Integer; begin m:= Length(X); n:= Length(Y); //We need one extra column and one extra row to be filled with zeroes SetLength(Result, m + 1, n + 1); //First column filled with zeros for i := 0 to m do Result[i, 0] := 0; //First row filled with zeros for j:= 0 to n do Result[0, j]:= 0; //Storing the lengths of the longest common subsequences //between prefixes of X and Y for i:= 1 to m do for j:= 1 to n do if X[i] = Y[j] then Result[i, j] := Result[i-1, j-1] + 1 else Result[i, j]:= Max(Result[i, j-1], Result[i-1, j]); end; class procedure TStringComparer.ComputeDifferences(aLCSMatrix: TIntArray; X, Y: string; i, j: Integer; aDifferences: TList<TDiff>); var CharDiff: TDiff; begin if (i > 0) and (j > 0) and (X[i] = Y[j]) then begin ComputeDifferences(aLCSMatrix, X, Y, i-1, j-1, aDifferences); CharDiff.Character:= X[i]; CharDiff.CharStatus:= '='; //The character did not change aDifferences.Add(CharDiff); end else if (j > 0) and ((i = 0) or (aLCSMatrix[i,j-1] >= aLCSMatrix[i-1,j])) then begin ComputeDifferences(aLCSMatrix, X, Y, i, j-1, aDifferences); CharDiff.Character:= Y[j]; CharDiff.CharStatus:= '+'; //The character was added aDifferences.Add(CharDiff); end else if (i > 0) and ((j = 0) or (aLCSMatrix[i,j-1] < aLCSMatrix[i-1,j])) then begin ComputeDifferences(aLCSMatrix, X, Y, i-1, j, aDifferences); CharDiff.Character:= X[i]; CharDiff.CharStatus:= '-'; //The character was removed aDifferences.Add(CharDiff); end; end; //This is a factory method class function TStringComparer.Compare(aString1, aString2: string): TList<TDiff>; var Matrix: TIntArray; begin Result:= TList<TDiff>.Create; Matrix:= LCSMatrix(aString1, aString2); ComputeDifferences(Matrix, aString1, aString2, Length(aString1), Length(aString2), Result); end; end.

Baixe aqui os fontes do exemplo do post

Download “Exemplo de Comparação entre strings” exemplo-comparacao-strings.zip – Baixado 37 vezes – 56 KB

Dúvidas ou sugestões? Deixe o seu comentário!

Baseado no post: http://www.yanniel.info/2012/01/lcs-string-comparison-in-delphi.html

  • Giovani Da Cruz
  • 5.289 views
  • 0 comentários
  • 26 de março de 2019

Está gostando do conteúdo? Apoie este trabalho você também!