DICAS

Visite a biblioteca de dicas da comunidade.

Saiba mais

ARTIGOS

Abordagens detalhadas sobre assuntos diversos.

Saiba mais

INICIANTES

Aprenda a programar de um modo simples e fácil.

Saiba mais

DOWNLOADS

Acesse os materiais exclusivos aos membros.

Saiba mais
voltar

PARA QUEM GOSTA DE DELPHI

Comparação de Strings com o Delphi

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.

comparacao-string

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;

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;

O programa irá fazer parecido com a imagem abaixo:
exemplo-comparacao-string

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.

Baixe aqui os fontes do exemplo do post

Download “Exemplo de Comparação entre strings”

exemplo-comparacao-strings.zip – Baixado 79 vezes – 56,29 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

Facebook Comments Box
  • Giovani Da Cruz
  • 6.222 views
  • 0 comentários
  • 26 de março de 2019

Está gostando do conteúdo? Considere pagar um cafezinho para nossa equipe!

Deixe um comentário

Ir ao topo

© 2024 Infus Soluções em Tecnologia - Todos os Direitos Reservados