AGB  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Code-Bibliothek Neuen Beitrag zur Code-Library hinzufügen Delphi Zwei Version-Strings (mit Buchstaben) vergleichen

Zwei Version-Strings (mit Buchstaben) vergleichen

Ein Thema von hypfvieh · begonnen am 17. Feb 2011 · letzter Beitrag vom 17. Feb 2011
Antwort Antwort
hypfvieh

Registriert seit: 1. Jan 2009
2 Beiträge
 
#1

Zwei Version-Strings (mit Buchstaben) vergleichen

  Alt 17. Feb 2011, 08:30
Hier ein simpler Code um 2 Versionsnummern zu prüfen.
Dazu werden die Buchstaben in ihre entsprechenden Zahlenwerte verwandelt, sämtlich Sonderzeichen werden ignoriert.

Limitierung: Wenn die Versionsnummer die Größe von Int64 überschreitet.

Ich habe hier 2 Versionen zur Verfügung gestellt, die erste ist getestet unter Delphi 2006 und Free Pascal 2.4.0.
Die zweite Version ist unter Delphi XE getestet worden.

Der Unterschied ist die Verwendung von "CharInSet" (in Delphi 2006 und FPC nicht verfügbar), um Kompatibilität mit WideStrings zu gewährleisten.
Die erste Version funktioniert zwar generell auch in den neueren Delphi Versionen, es wird aber fehlende WideString Kompatibilität angemahnt.

Delphi 2006/Free Pascal Version:
Delphi-Quellcode:
function checkversion(ver1,ver2 : string) : byte;
var i : integer;
    tmp1,tmp2 : string;
    cver1,cver2 : int64;
begin
{
  Return values:
      0: versions are equal
      1: ver1 is bigger then ver2
      2: ver2 is bigger then ver1
    253: ver1 is too big (could not be converted to int64)
    254: ver2 is too big (could not be converted to int64)
}


  tmp1 := '';
  tmp2 := '';

  for i := 1 to length(ver1) do begin
    if (ver1[i] in ['a'..'z']) or (ver1[i] in ['A'..'Z']) then
      tmp1 := tmp1 + inttostr(Ord(ver1[i]));
    if (ver1[i] in ['0'..'9']) then
      tmp1 := tmp1 + ver1[i];
  end;
  for i := 1 to length(ver2) do begin
    if (ver2[i] in ['a'..'z']) or (ver2[i] in ['A'..'Z']) then
      tmp2 := tmp2 + inttostr(Ord(ver2[i]));
    if (ver2[i] in ['0'..'9']) then
      tmp2 := tmp2 + ver2[i];
  end;

  if not TryStrToInt64(tmp2,cver2) then begin
        checkversion := 254;
        exit;
  end;
  if not TryStrToInt64(tmp1,cver1) then begin
        checkversion := 253;
        exit;
  end;



  if ver1 > ver2 then
    checkversion := 1
  else if ver2 > ver1 then
    checkversion := 2
  else
    checkversion := 0;
end;
Delphi XE Version:
Delphi-Quellcode:
function checkversion(ver1,ver2 : string) : byte;
var i : integer;
    tmp1,tmp2 : string;
    cver1,cver2 : int64;
begin
{
  Return values:
      0: versions are equal
      1: ver1 is bigger then ver2
      2: ver2 is bigger then ver1
    253: ver1 is too big (could not be converted to int64)
    254: ver2 is too big (could not be converted to int64)
}


  tmp1 := '';
  tmp2 := '';

  for i := 1 to length(ver1) do begin
    if (CharInSet(ver1[i],['a'..'z'])) or (CharInSet(ver1[i],['A'..'Z'])) then
      tmp1 := tmp1 + inttostr(Ord(ver1[i]));
    if (CharInSet(ver1[i],['0'..'9'])) then
      tmp1 := tmp1 + ver1[i];
  end;
  for i := 1 to length(ver2) do begin
    if (CharInSet(ver2[i],['a'..'z'])) or (CharInSet(ver2[i],['A'..'Z'])) then
      tmp2 := tmp2 + inttostr(Ord(ver2[i]));
    if (CharInSet(ver2[i],['0'..'9'])) then
      tmp2 := tmp2 + ver2[i];
  end;

  if not TryStrToInt64(tmp2,cver2) then begin
    checkversion := 254;
    exit;
  end;
  if not TryStrToInt64(tmp1,cver1) then begin
    checkversion := 253;
    exit;
  end;


  if cver1 > cver2 then
    checkversion := 1
  else if cver2 > cver1 then
    checkversion := 2
  else
    checkversion := 0;
end;
Aufruf-Beispiel:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var test : byte;
begin
  test := checkversion(edit1.text,edit2.text);

  if test >= 253 then
    showmessage('Error while comparing')
  else if test = 2 then
    showmessage('Version 2 is newer')
  else if test = 1 then
    showmessage('Version 1 is newer')
  else
    showmessage('Versions are equal');
end;
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
28.071 Beiträge
 
Delphi XE3 Professional
 
#2

AW: Zwei Version-Strings (mit Buchstaben) vergleichen

  Alt 17. Feb 2011, 08:55
'1.97' = '1.a'
'1.23' = '12.3'
ich glaub ein/zwei Sachen mußt'e noch anpassen.

Tipp: Strings nicht in Zahlen umwandeln und die Strings vorher an Zahlen-/Buchstabengrenzen aufteilen, sowie den Punkt nicht ignorieren und alles was über Punkte (das sind ja typische Versionsnummernteileteiler ) getrennt vergleichen.

Als Rückgabewert lieber einen "verständlicheren" Enum oder einfach nur ein TCompareValue TValueRelationship (bei Fehlern eine Exception werfen) verwenden.

[edit]
Komisch, mir war so, als wenn es mal ein TCompareValue gab.
Delphi-Quellcode:
type
  TValueRelationship = -1..1;

const
  LessThanValue = Low(TValueRelationship);
  EqualsValue = 0;
  GreaterThanValue = High(TValueRelationship);
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
Delphi-Tage 2005-2014

Geändert von himitsu (17. Feb 2011 um 09:11 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von GPRSNerd
GPRSNerd

Registriert seit: 30. Dez 2004
Ort: Ruhrpott
172 Beiträge
 
Delphi XE4 Professional
 
#3

AW: Zwei Version-Strings (mit Buchstaben) vergleichen

  Alt 17. Feb 2011, 09:14
'1.97' = '1.a'
'1.23' = '12.3'
ich glaub ein/zwei Sachen mußt'e noch anpassen.
Tipp: Strings nicht in Zahlen umwandeln und die Strings vorher an Zahlen-/Buchstabengrenzen aufteilen, sowie den Punkt nicht ignorieren und alles was über Punkte (das sind ja typische Versionsnummernteileteiler ) getrennt vergleichen.
Jau, für die Problematiken benutze ich ähnlichen Code wie den hier:

Delphi-Quellcode:
      //Aus 12.34.56.7890 eine auswertbare Zahl 1234567890 machen
      //Funktioniert nur solange die Zahlen 2/4(build)stellig bleiben!
      V1 := (StrToInt(Params[0]) * 100000000) +
            (StrToInt(Params[1]) * 1000000) +
            (StrToInt(Params[2]) * 10000) +
            (StrToInt(Params[3]) * 1);
      V2 := (StrToInt(Params[4]) * 100000000) +
            (StrToInt(Params[5]) * 1000000) +
            (StrToInt(Params[6]) * 10000) +
            (StrToInt(Params[7]) * 1);
Kann man ja dann noch entsprechend generalisieren, abh. vom Format des Versionstrings.
Stefan
  Mit Zitat antworten Zitat
Benutzerbild von GPRSNerd
GPRSNerd

Registriert seit: 30. Dez 2004
Ort: Ruhrpott
172 Beiträge
 
Delphi XE4 Professional
 
#4

AW: Zwei Version-Strings (mit Buchstaben) vergleichen

  Alt 17. Feb 2011, 14:09
Hier mal ein Versuch, der sich auf numerische Strings (z.B. "1234.1224.1234.1234") mit Separator (Char, default ".") beschränkt.
Die Anzahl der Teilstrings und deren nummerische Größe ist nur limitiert durch die Größe von Int64, da keine Summenzahl aus den Teilstrings gebildet wird, sondern alle Päarchen einzeln miteinander verglichen werden, bis ein eindeutiges Ergebnis feststeht.

Delphi-Quellcode:
type
  //Returntype für Versionsnummern vergleichen
  TValueRelationship = -1..1;

const
  //Returnvalues für Versionsnummern vergleichen
  LessThanValue = Low(TValueRelationship);
  EqualsValue = 0;
  GreaterThanValue = High(TValueRelationship);

function IsNumeric(const s: String): Boolean;
var
  i: Integer;
begin
  Result := False;
  for i := 1 to Length(s) do
    if not CharInSet(s[i], ['0'..'9']) then exit;
  Result := True;
end;

function CompareVersionStrings(const V1, V2: string;
                               const Separator: char = '.'): TValueRelationship;
var
  iV1, iV2: Int64;
  slV1, slV2: TStringList;
  i: Integer;
begin
  Result := EqualsValue; //temp

  //Übergebene Parameter validieren
  if ((V1='') or (V2='') or (Separator='')) then
  begin
    Raise Exception.CreateFmt('CompareVersionStrings: Leere Parameter nicht erlaubt ("%S", "%S", "%S")', [V1, V2, Separator]);
    Exit;
  end;

  slV1 := TStringList.Create;
  slV2 := TStringList.Create;
  try

    //Strings in Teilstrings mit Stringlists zerlegen
    slV1.Delimiter := Separator;
    slV1.DelimitedText := V1;
    slV2.Delimiter := Separator;
    slV2.DelimitedText := V2;
    if ((slV1.Count<>slV2.Count) or (slV1.Count=0) or (slV2.Count=0)) then
    begin
      Raise Exception.CreateFmt('CompareVersionStrings: Anzahl der Teilstrings ist nicht identisch (%D bei "%S", %D bei "%S")', [slV1.Count, V1, slV2.Count, V2]);
      Exit;
    end;

    //Teilstrings auswerten
    for i := 0 to slV1.Count - 1 do
    begin
      if ((slV1[i]='') or (slV2[i]='')) then
      begin
        Raise Exception.CreateFmt('CompareVersionStrings: Leere Teilstrings nicht erlaubt ("%S" bei "%S", "%S" bei "%S")', [slV1[i], V1, slV2[i], V2]);
        Exit;
      end;

      if ((not IsNumeric(slV1[i])) or (not IsNumeric(slV2[i]))) then
      begin
        Raise Exception.CreateFmt('CompareVersionStrings: Teilstrings sind nicht numerisch ("%S" bei "%S", "%S" bei "%S")', [slV1[i], V1, slV2[i], V2]);
        Exit;
      end;

      //In Integerzahlen konvertieren
      try
        iV1 := StrToInt(slV1[i]);
        iV2 := StrToInt(slV2[i]);
      except
        Raise Exception.CreateFmt('CompareVersionStrings: Konvertierung nach Integer nicht erfolgreich ("%S" bei "%S", "%S" bei "%S")', [slV1[i], V1, slV2[i], V2]);
        Exit;
      end;

      //Jetzt Integerzahlen vergleichen
      if iV1<iV2 then
      begin
        Result := LessThanValue;
        Break; //Eindeutiges Ergebnis, Schleife abbrechen
      end
      else if iV1>iV2 then
      begin
        Result := GreaterThanValue;
        Break; //Eindeutiges Ergebnis, Schleife abbrechen
      end
      else
      begin
        //Immer noch gleich, nächstes Paar vergleichen
      end;
    end;

  finally
    FreeAndNil(slV1);
    FreeAndNil(slV2);
  end;
end;
Die folgenden Positiv- und Exception-Unittests waren damit erfolgreich unter Delphi 2010:
Delphi-Quellcode:
  Assert(EqualsValue = CompareVersionStrings('0', '0'));
  Assert(EqualsValue = CompareVersionStrings('1', '1'));
  Assert(EqualsValue = CompareVersionStrings('1.2', '1.2'));
  Assert(EqualsValue = CompareVersionStrings('1.2.3', '1.2.3'));
  Assert(EqualsValue = CompareVersionStrings('1.2.3.4', '1.2.3.4'));
  Assert(EqualsValue = CompareVersionStrings('9999.9999.9999.9999', '9999.9999.9999.9999'));
  Assert(EqualsValue = CompareVersionStrings('99999.99999.99999.99999', '99999.99999.99999.99999'));
  Assert(EqualsValue = CompareVersionStrings('99999.99999.99999.99999.99999', '99999.99999.99999.99999.99999'));

  Assert(LessThanValue = CompareVersionStrings('0', '1'));
  Assert(LessThanValue = CompareVersionStrings('1', '2'));
  Assert(LessThanValue = CompareVersionStrings('1.2', '1.3'));
  Assert(LessThanValue = CompareVersionStrings('1.2.3', '1.2.4'));
  Assert(LessThanValue = CompareVersionStrings('1.2.3.4', '1.2.3.5'));
  Assert(LessThanValue = CompareVersionStrings('9991.9999.9999.9999', '9999.9999.9999.9999'));
  Assert(LessThanValue = CompareVersionStrings('9999.9991.9999.9999', '9999.9999.9999.9999'));
  Assert(LessThanValue = CompareVersionStrings('9999.9999.9991.9999', '9999.9999.9999.9999'));
  Assert(LessThanValue = CompareVersionStrings('9999.9999.9999.9991', '9999.9999.9999.9999'));
  Assert(LessThanValue = CompareVersionStrings('99999.99999.99999.99991', '99999.99999.99999.99999'));
  Assert(LessThanValue = CompareVersionStrings('99999.99999.99999.99999.99991', '99999.99999.99999.99999.99999'));

  Assert(GreaterThanValue = CompareVersionStrings('1', '0'));
  Assert(GreaterThanValue = CompareVersionStrings('2', '1'));
  Assert(GreaterThanValue = CompareVersionStrings('1.3', '1.2'));
  Assert(GreaterThanValue = CompareVersionStrings('1.2.4', '1.2.3'));
  Assert(GreaterThanValue = CompareVersionStrings('1.2.3.5', '1.2.3.4'));
  Assert(GreaterThanValue = CompareVersionStrings('9999.9999.9999.9999', '9991.9999.9999.9999'));
  Assert(GreaterThanValue = CompareVersionStrings('9999.9999.9999.9999', '9999.9991.9999.9999'));
  Assert(GreaterThanValue = CompareVersionStrings('9999.9999.9999.9999', '9999.9999.9991.9999'));
  Assert(GreaterThanValue = CompareVersionStrings('9999.9999.9999.9999', '9999.9999.9999.9991'));
  Assert(GreaterThanValue = CompareVersionStrings('99999.99999.99999.99999', '99999.99999.99999.99991'));
  Assert(GreaterThanValue = CompareVersionStrings('99999.99999.99999.99999.99999', '99999.99999.99999.99999.99991'));

  Assert(EqualsValue = CompareVersionStrings('1,2', '1,2', ','));
  Assert(LessThanValue = CompareVersionStrings('1,2', '1,3', ','));
  Assert(GreaterThanValue = CompareVersionStrings('1,3', '1,2', ','));
  Assert(GreaterThanValue = CompareVersionStrings('9999#9999#9999#9999', '9999#9999#9999#9998', '#'));

  Vergleich: TValueRelationship;
  //Exceptions: Leere Parameter
  try
    Vergleich := CompareVersionStrings('1', '');
  except
  end;
  try
    Vergleich := CompareVersionStrings('', '2');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1', '2', #0);
  except
  end;

  //Exceptions: Ungleiche Counts
  try
    Vergleich := CompareVersionStrings('1.2.3', '1.2.3.4');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2.3.4', '1.2.3');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2.3', '1.2..4');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2..4', '1.2.3');
  except
  end;

  //Exceptions: Leere Teilstrings
  try
    Vergleich := CompareVersionStrings('1.2..4', '1.2.3.4');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2.3.4', '1.2..4');
  except
  end;

  //Exceptions: Nichtnumerisch
  try
    Vergleich := CompareVersionStrings('1.2.3A', '1.2.3');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2.3', '1.2.3B');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2.3A', '1.2.3B');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2.3.A', '1.2.3.4');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2.3.4', '1.2.3.B');
  except
  end;
  try
    Vergleich := CompareVersionStrings('1.2.3.A', '1.2.3.B');
  except
  end;
//Edit: Exceptionhandling angepasst nach Tests.
Stefan

Geändert von GPRSNerd (17. Feb 2011 um 17:48 Uhr)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:07 Uhr.
Powered by vBulletin® Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2014 by Daniel R. Wolf