Thema: NatCompare

Einzelnen Beitrag anzeigen

Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.077 Beiträge
 
Delphi XE2 Professional
 
#1

NatCompare

  Alt 22. Sep 2012, 02:39
Vor kurzem wurde ich durch den Beitrag http://www.delphipraxis.net/1181723-post35.html und insbesondere durch den Kommentar
Juhu, es klappt, ich könnte tanzen...
auf die diesem Beitrag http://www.delphipraxis.net/1181699-post21.html angehängte "NatCompare.pas" aufmerksam.

Leider kann ich XxnemesisxX49s Begeisterung überhaupt nicht teilen, weil die Unit mehrere Fehler enthält.

Im Detail:

Wenn einer der zu vergleichenden Strings leer ist, kommt es vor, dass eine Exception "xxx ist kein Integerwert" auftritt.
Ursache :
In function GetNext(const S: String; var Start: Integer; var IsNumber: Boolean): String; wird zwar erkannt, dass "nichts mehr da ist", was verglichen werden könnte, jedoch wird IsNumber nicht = false gesetzt, was in der aufrufenden Funktion NaturalCompareFunc dazu führen kann, dass versucht wird einen leeren String mit IntToStr in einen Integerwert umzuwandeln.
Abhilfe :
In GetText als erste Zeile IsNumber:=false; einfügen.

Wenn beide Strings an der gleichen Position Zahlen enthalten, und eine dieser Zahlen größer als maxint ist, wird ebenfalls eine Exception geworfen.
Abhilfe:
In der Funktion NaturalCompareFunc die Zeile
Result := StrToInt(P1) - StrToInt(P2)
ersetzen durch
result:=NumCompare(P1,P2)
Die weiter unten stehende NumCompare verarbeitet auch kilometerlange Zahlen.

Die in den Funktionen NaturalCompareStr und NaturalCompareText den Stringvergleichen nachgeschaltete Funktion IntSign ist fehlerhaft.

Delphi-Quellcode:
function IntSign(x:integer):Integer;
begin
   if x > 0 then
      Result := 1
   else if x < 0 then
      Result := -1;
end;
Was passiert wohl, wenn x = 0 ist ?
Richtig, das Resultat ist undefiniert, zumindest unter XE2 wenn die Optimierung ausgeschaltet ist. Bei anderen Versionen mag das anders sein. Auf jeden Fall sollte man sich nicht darauf verlassen, dass auch bei zukünftigen Versionen das EAX-Register unverändert bleibt. Ein weiteres Argument ist, dass bei 64-Bit Versionen der Parameter "x" in RCX übergeben wird, das Resultat aber weiterhin in RAX erwartet wird. Fairerweise muss man aber zugestehen, dass diese Entwicklung bei Erstellung des Codes wohl nicht absehbar war.
Abhilfe :
Als erste Zeile
Result:=x;
einfügen.


Delphi-Quellcode:
// Vergleicht die numerischen Werte zweier Strings.
// Achtung : Die aufrufende Funktion muss sicherstellen, dass S1 und S2 nicht leer sind
// und ausschließlich aus Zeichen "0".."9" besteht.
FUNCTION NumCompare(const S1,S2:String):integer;
var n1,n2:integer; p1,p2:PChar;
begin
   p1:=@s1[1];
   p2:=@s2[1];
   while p1^='0do inc(p1);
   while p2^='0do inc(p2);
   n1:=@s1[Length(s1)]-p1;
   n2:=@s2[Length(s2)]-p2;
   result:=n1-n2;
   if (result<>0) or (n1<0) and (n2<0) then exit;
   repeat
      result:=Ord(p1^)-Ord(p2^);
      inc(p1);
      inc(p2);
   until (result<>0) or (p1^=#0);
end;
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat