Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CompareText

52 views
Skip to first unread message

Thomas Schwobe

unread,
Nov 5, 2012, 12:43:09 PM11/5/12
to
Hallo,

zum Sortieren von Probennamen benutze ich im OnCompare CompareText
(Rückgabe -1, 0, 1). Es kommt dabei aber so was raus:

Sample1
Sample10
Sample2

Soll aber

Sample1
Sample2
Sample10

sein. Gibt es da eine andere (schnelle) Compare Funktion?

Danke und beste Grüße
Thomas

Arno Garrels

unread,
Nov 5, 2012, 12:56:26 PM11/5/12
to
Thomas Schwobe wrote:
> Hallo,
>
> zum Sortieren von Probennamen benutze ich im OnCompare CompareText
> (Rückgabe -1, 0, 1). Es kommt dabei aber so was raus:
>
> Sample1
> Sample10
> Sample2
>
> Soll aber
>
> Sample1
> Sample2
> Sample10
>
> sein. Gibt es da eine andere (schnelle) Compare Funktion?

Schnell? Bestimmt nicht, eher grottenlangsam. Ein String ist ein String
und ein Integer ist ein Integer. Trick oder Würgaround wäre die Integer
im String mit führenden Nullen darzustellen, also

> Sample01
> Sample02
> Sample10

--
Arno


Achim Kalwa

unread,
Nov 6, 2012, 10:07:13 AM11/6/12
to
Moin,

Thomas Schwobe wrote:
>
> zum Sortieren von Probennamen benutze ich im OnCompare CompareText
> (Rückgabe -1, 0, 1). Es kommt dabei aber so was raus:
>
> Sample1
> Sample10
> Sample2
>
> Soll aber
>
> Sample1
> Sample2
> Sample10
>
> sein. Gibt es da eine andere (schnelle) Compare Funktion?

Ja, die gibt es tatsächlich: StrCmpLogicalW() ab Windows XP:

> http://msdn.microsoft.com/en-us/library/windows/desktop/bb759947(v=vs.85).aspx

Leider ist diese Funktion nicht in den Delphi-Units deklariert. Zur
Abhilfe entweder die Jedi Windows API (JWA) installieren und die Unit
JwaShlWApi.pas einbinden; oder die Function als external deklarieren:

function StrCmpLogicalW(psz1, psz2: PWideChar): Integer; stdcall;
external 'shlwapi.dll';

Ich habe mir dann noch einen einfachen Wrapper gebaut:

function CompareStringLogical(const S1, S2: string): Integer;
begin
Result := StrCmpLogicalW(PChar(S1), PChar(S2))
end;

HTH
Achim

Arno Garrels

unread,
Nov 6, 2012, 11:17:17 AM11/6/12
to
Achim Kalwa wrote:
>> Gibt es da eine andere (schnelle) Compare Funktion?
>
> Ja, die gibt es tatsächlich: StrCmpLogicalW() ab Windows XP:
>
>> http://msdn.microsoft.com/en-us/library/windows/desktop/bb759947(v=vs.85).aspx

Gut zu wissen, aber ist die schnell? Schließlich muß man dafür den String parsen etc..

Naja, "schnell" ist relativ ;)

--
Arno

Thomas Schwobe

unread,
Nov 7, 2012, 12:03:59 PM11/7/12
to
Hallo Arno,

"Arno Garrels" schrieb im Newsbeitrag news:k7bd58$ku4$1...@online.de...

>Naja, "schnell" ist relativ ;)

ich glaube wir wissen alle, dass es bei Strings nicht wirklich schnell geht.
Aber schön, das es mit StrCmpLogicalW schon etwas "Erprobtes" gibt.

Thomas

Gunnar

unread,
Nov 7, 2012, 2:59:12 PM11/7/12
to
"Thomas Schwobe" schrieb im Newsbeitrag
news:k7e4eu$9nb$1...@news.albasani.net...

> Aber schön, das es mit StrCmpLogicalW schon etwas "Erprobtes" gibt.

Naja, erprobt schon, aber

Note Behavior of this function, and therefore the results it returns, can
change from release to release. It should not be used for canonical sorting
applications.

Auf sowas würde ich mich nicht unbedingt verlassen wollen.

-Gunnar

Achim Kalwa

unread,
Nov 8, 2012, 9:34:42 AM11/8/12
to
Moin,
In der Tat hat sich das Verhalten dieser Funktion zwischen XP und Vista
etwas geändert:
> http://blogs.msdn.com/b/michkap/archive/2006/10/01/778990.aspx

Zum Sortieren von Bestellnummern (String) ist es aber prima geeignet :-)

Übrigens gibt es dieses Verhalten ab Windows 7 auch direkt in
CompareString() bzw. CompareStringEx() mit dem Flag SORT_DIGITSASNUMBERS:

> http://msdn.microsoft.com/en-us/library/windows/desktop/dd317761(v=vs.85).aspx

Achim

Arno Garrels

unread,
Nov 8, 2012, 1:36:01 PM11/8/12
to

"Thomas Schwobe" <Thomas....@screensoft.de> schrieb im Newsbeitrag news:k7e4eu$9nb$1...@news.albasani.net...
> Hallo Arno,
>
> "Arno Garrels" schrieb im Newsbeitrag news:k7bd58$ku4$1...@online.de...
>
>>Naja, "schnell" ist relativ ;)
>
> ich glaube wir wissen alle, dass es bei Strings nicht wirklich schnell geht.

Klar, aber Integers in den Strings zu finden und zu vergleichen ist bestimmt
noch viel langsamer.

--
Arno

Achim Kalwa

unread,
Nov 9, 2012, 11:50:26 AM11/9/12
to
Hallo ihr Geschwindigkeitsapostel :-)

>>> Naja, "schnell" ist relativ ;)
>>
>> ich glaube wir wissen alle, dass es bei Strings nicht wirklich schnell geht.
>
> Klar, aber Integers in den Strings zu finden und zu vergleichen ist bestimmt
> noch viel langsamer.

Ich habe ein kleines Testprogramm geschrieben, welches eine StringList
mit 100.000 Zufalls-Strings bestehend aus Buchstaben und Zahlen
sortiert: Einmal mittels "CompareString", dann eine Kopie der Liste
mittels "StrCmpLogicalW".

Ergebnis:
Wie schon vermutet ist StrCmpLogicalW "deutlich" langsamer, und zwar um
ca. den Faktor 3,6:

> 100000 Strings sortieren:
> CompareString: 260 ms
> StrCmpLogicalW: 940 ms

Insgesamt ist das (für mich) aber immer noch schnell genug.
Typischerweise habe ich 100 bis 1000 Strings zu sortieren; und das geht
Quasi in Nullzeit :-)

Leider habe ich noch keine Möglichkeit gefunden, diese Sort-Function in
Firebird SQL zu verwenden, um die Ergebnismenge natürlich zu sortieren:

> select * from ARTIKEL where (...) order by NUMMER

Irgendeine Idee?

Achim



Arno Garrels

unread,
Nov 9, 2012, 1:39:27 PM11/9/12
to
Achim Kalwa wrote:
> Wie schon vermutet ist StrCmpLogicalW "deutlich" langsamer, und zwar
> um ca. den Faktor 3,6:
>
>> 100000 Strings sortieren:
>> CompareString: 260 ms
>> StrCmpLogicalW: 940 ms

Wie erwartet. Dass das für viele Anwendungen völlig ausreichend
schnell/langsam ist, habe ich nie bestritten, grottenlangsam ist's
trotzdem, verglichen mit dem klassischen Stringvergleich.

--
Arno

Matthias Hanft

unread,
Nov 10, 2012, 4:07:31 AM11/10/12
to
Achim Kalwa schrieb:
>
> Leider habe ich noch keine Möglichkeit gefunden, diese Sort-Function in
> Firebird SQL zu verwenden, um die Ergebnismenge natürlich zu sortieren:
>> select * from ARTIKEL where (...) order by NUMMER
> Irgendeine Idee?

Mit den geeigneten Werkzeugen (vermutlich nicht Delphi) kann man ja Fire-
bird-UDFs schreiben. Dann könnte man die Zahlenspalte in einen View schreiben,
den abfragen und nach dieser Spalte sortieren... nur mal so spontan angedacht,
selber noch nicht probiert :-)

Gruß Matthias.

Arno Garrels

unread,
Nov 10, 2012, 11:39:26 AM11/10/12
to
Thomas Schwobe wrote:

> ich glaube wir wissen alle, dass es bei Strings nicht wirklich
> schnell geht. Aber schön, das es mit StrCmpLogicalW schon etwas
> "Erprobtes" gibt.

Schön für dich, wenn dir Microsoft so ein warmes und geborgenes Gefühl gibt, ich
jedenfalls würde immer versuchen, solche relativ simplen Routinen mit eigenen-
oder anderen Delphi-Routinen zu ersetzen. Deshalb hier mal was schnelles Experimentelles,
erfunden nach dem dritten Radeberger, also Vorsicht!! Kann StrCmpLogicalW eigentlich
Int64, Vorzeichen, Fließkomma?:

{code}
function MyCompare(P1, P2: PChar): Integer;

function GetNextInt(var P: PChar): Integer;
begin
Result := 0;
while True do
begin
case P^ of
'0'..'9' : Result := Result * 10 + Ord(P^) - Ord('0');
else
Exit;
end;
Inc(P);
end;
end;

const
LDigits: TSysCharSet = ['0'..'9'];
begin
while (P1^ <> #0) and (P2^ <> #0) do
begin
if CharInSet(P1^, LDigits) then
begin
if CharInSet(P2^, LDigits) then
begin
Result := GetNextInt(P1) - GetNextInt(P2);
if Result = 0 then
Continue
else
Exit;
end
else begin
Result := Ord(P1^) - Ord(P2^);
Exit;
end;
end
else if (P1^ <> P2^) then
begin
Result := Ord(P1^) - Ord(P2^);
Exit;
end
else begin
Inc(P1);
Inc(P2);
end;
end;
Result := Ord(P1^) - Ord(P2^);
end;
{code}

--
Arno
0 new messages