TStringlist sortieren

Für Fragen von Einsteigern und Programmieranfängern...
malabarista
Beiträge: 321
Registriert: Sa 11. Jun 2016, 12:16
OS, Lazarus, FPC: Linux Mint 18.1 L1.6.2-1 FPC 3.0.0
CPU-Target: 64Bit
Wohnort: Konstanz

TStringlist sortieren

Beitrag von malabarista »

Ich möchte eine TStringlist, in der in Strings umgewandelte Intergerwerte stehen, sortieren und bin dabei auf folgendes Problem gestossen:
Zahlen mit führenden Blanks werden anders sortiert als Zahlen mit führenden Nullen.

Beispiel1:

Code: Alles auswählen

 
'  13'
'  14'
'   6'
 

Beispiel2:

Code: Alles auswählen

 
'  06'
'  13'
'  14'
 


Kann ich das in irgendwelche Einstellungen für die TStinglist ändern, sodass immer die 6 vor der 13 steht ? Oder muss ich immer die führenden Nullen dabei haben ?

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: TStringlist sortieren

Beitrag von Warf »

Du kannst die Funktion CustomSort verwenden, und dabei eine eigene Komperatorfunktion angeben

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TStringlist sortieren

Beitrag von Mathias »

Zahlen mit führenden Blanks werden anders sortiert als Zahlen mit führenden Nullen.

Der Grund dafür ist, das es der normalen Sortierfunktion egal ist ob es sich um eine Ziffer handelt. Diese sortiert einfach nach den ASCII-Zeichen, und Space ist kleiner als die Ziffern.

Ich habe es gerade probiert, aber das Egebniss ist trotzdem nicht wie erwartet. :roll:

Code: Alles auswählen

  sl.Add('  13');
  sl.Add('  14');
  sl.Add('  11');
  sl.Add('   6');
  sl.Add('   5');
  sl.Add('  05');
  sl.Sort;
  ShowMessage(sl.Text); \0

Code: Alles auswählen

05
  11
  13
  14
   5
   6

Space hat #32 und die Ziffern fangen erst bei #60.

Ich habe noch was probiert:

Code: Alles auswählen

  sl.Add('  13');
  sl.Add('  14');
  sl.Add('  11');
  sl.Add('   6');
  sl.Add('   5');
  sl.Add('  05');
 
  sl.Add('##13');
  sl.Add('##14');
  sl.Add('##11');
  sl.Add('###6');
  sl.Add('###5');
  sl.Add('##05');
  sl.Sort;
  ShowMessage(sl.Text);\0

Code: Alles auswählen

  05
##05
  11
##11
  13
##13
  14
##14
   5
###5
   6
###6

Anscheinend unterscheidet die Sonderfunktion nicht mal zwischen #32 und #35. :roll:
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TStringlist sortieren

Beitrag von wp_xyz »

Keine Ahnung, was du da machst, aber Windows und Mint 18.1 sortieren in diesem Programm wie erwartet:

Code: Alles auswählen

program Project1;
 
{$mode objfpc}{$H+}
 
uses
  Classes;
 
var
  sl: TStringList;
  i: Integer;
 
begin
  sl := TStringList.Create;
 
  sl.Add('##13');
  sl.Add('##14');
  sl.Add('##11');
  sl.Add('###6');
  sl.Add('###5');
  sl.Add('##05');
 
  sl.Add('  13');
  sl.Add('  14');
  sl.Add('  11');
  sl.Add('   6');
  sl.Add('   5');
  sl.Add('  05');
 
  for i:=0 to sl.Count-1 do WriteLn(sl[i]);
 
  WriteLn;
  sl.Sort;
  for i:=0 to sl.Count-1 do WriteLn(sl[i]);
end.


Code: Alles auswählen

##13
##14
##11
###6
###5
##05
  13
  14
  11
   6
   5
  05
 
   5
   6
  05
  11
  13
  14
###5
###6
##05
##11
##13
##14

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TStringlist sortieren

Beitrag von Mathias »

Keine Ahnung, was du da machst, aber Windows und Mint 18.1 sortieren in diesem Programm wie erwartet:

Ich habe es nochmals probiert, aber diesmal mit Wine und FPC 3.0.2, da bekomme ich das gleiche Ergebniss wie du.

Nativ habe ich unter Mint FPC 3.1.1 , vielleicht liegt es daran.
Ich habe genauer geguckt, bei Pascal-Versionen landen beim TStringList.QuickSort und dies sieht identisch aus.

Einziger Unterschied den ich erkenne kann, bei 3.0.2 fängt die Funktion bei Zeile 1115 an und bei 3.1.1 bei Zeile 1263.

Ich habe noch etwas gefunden:
FPC 3.0.2:

Code: Alles auswählen

function AnsiCompareStr(const S1, S2: string): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  begin
    result:=widestringmanager.CompareStrAnsiStringProc(s1,s2);
  end;
 
function AnsiCompareText(const S1, S2: string): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  begin
    result:=widestringmanager.CompareTextAnsiStringProc(s1,s2);
  end;


FPC 3.1.1:

Code: Alles auswählen

function AnsiCompareStr(const S1, S2: string): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  begin
    // CAPSIZEINT is no-op if Sizeof(Sizeint)<=SizeOF(Integer)
    result:=CAPSIZEINT(widestringmanager.CompareStrAnsiStringProc(s1,s2));
  end;
 
function AnsiCompareText(const S1, S2: string): integer;{$ifdef SYSUTILSINLINE}inline;{$endif}
  begin
    // CAPSIZEINT is no-op if Sizeof(Sizeint)<=SizeOF(Integer)
    result:=CAPSIZEINT(widestringmanager.CompareTextAnsiStringProc(s1,s2));
  end;   \0
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TStringlist sortieren

Beitrag von wp_xyz »

Auch fpc3.1.1 (r36505 vom 15.6., 32 bit)) unter original Win10 macht bei mir keine Probleme. Nenne bitte genau die Bedingungen, unter denen du die falsche Sortierung erhältst, poste das zugehörige Programm.

[EDIT]
Wenn ich in der Linux-Version die Unit cwstring ins "uses" meines obigen Testprogramms aufnehme, entsteht eine Sortierung ähnlich wie bei dir. Hierzu steht in https://www.freepascal.org/docs-html/3. ... index.html: "initializes the widestring manager record of the system unit with an implementation that uses collation and conversion routines" ("collation" = "Sortierreihenfolge")

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TStringlist sortieren

Beitrag von Mathias »

poste das zugehörige Programm.

Im Anhang mein Code.

Nenne bitte genau die Bedingungen, unter denen du die falsche Sortierung erhältst,

Nützt dir dies etwas ?
Oder gibt rs eine Möglichkeit, das FPC die Revision ausspuckt ?

Code: Alles auswählen

 $ fpc -v
Free Pascal Compiler version 3.1.1 [2017/06/16] for x86_64
Copyright (c) 1993-2017 by Florian Klaempfl and others
Fatal: No source file name in command line
Fatal: Compilation aborted
Error: /usr/bin/ppcx64 returned an error exitcode
Dateianhänge
sl_sort_test.tar.gz
(125.68 KiB) 59-mal heruntergeladen
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: TStringlist sortieren

Beitrag von mse »

Die einzelnen Zeichenkategorien haben bei der Unicode Sortierung verschiedene Wertigkeiten:
http://unicode.org/reports/tr10/#Multi_Level_Comparison
Leerzeichen und andere Zeichen werden nur berücksichtigt, wenn die Buchstaben und Ziffern übereinstimmen.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TStringlist sortieren

Beitrag von wp_xyz »

Ich sehe jetzt auch die seltsame Sortierung unter Mint (fpc 3.02). "Schuld" ist die in deinem Projekt über LCL eingebundene Unit LazUF8, die cwstring verwendet (In meiner Konsolen-Version war diese nicht eingebunden):

Code: Alles auswählen

unit LazUTF8;
...
uses
  {$ifdef unix}
  // WideCompare* functions on Unix requires this. Must be used although it pulls in clib.
  cwstring,
  {$endif}     
  ...

Was lernen wir daraus? Wenn man plattformübergreifend eine bestimmte Sortierreihenfolge will, kann man sich auf nichts verlassen, sondern muss CustomSort (o.ä.) aufrufen.

malabarista
Beiträge: 321
Registriert: Sa 11. Jun 2016, 12:16
OS, Lazarus, FPC: Linux Mint 18.1 L1.6.2-1 FPC 3.0.0
CPU-Target: 64Bit
Wohnort: Konstanz

Re: TStringlist sortieren

Beitrag von malabarista »

Ich habe es jetzt plattformübergreifend auf meine Art gelöst:
bei Zahlen werden immer führende Nullen vorangesetzt.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TStringlist sortieren

Beitrag von wp_xyz »

Finde ich nicht gut, wirkt "behelfsmäßig". Die saubere Lösung wäre eine eigene Vergleichsroutine für CustomSort - siehe Anhang.
Dateianhänge
stringlist_customsort.zip
(2.1 KiB) 94-mal heruntergeladen

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TStringlist sortieren

Beitrag von Mathias »

Die saubere Lösung wäre eine eigene Vergleichsroutine für CustomSort

Aber wehe es befindet sich Buchstaben in der StringList, dann knallt es.
Trim kannte ich bis jetzt nicht, um diesen Befehl wäre ich auch schon froh gewesen. :wink:

ch sehe jetzt auch die seltsame Sortierung unter Mint (fpc 3.02). "Schuld" ist die in deinem Projekt über LCL eingebundene Unit LazUF8, die cwstring verwendet (In meiner Konsolen-Version war diese nicht eingebunden):

Dies habe ich jetzt auch probiert, in der Console ist es anders, irgendwie doof.
Somit liegt dies nicht an der Trunk von FPC.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TStringlist sortieren

Beitrag von wp_xyz »

Mathias hat geschrieben:Aber wehe es befindet sich Buchstaben in der StringList, dann knallt es.

Natürlich. Wenn Buchstaben drinnen sind, dann hoffe ich, dass der Programmierer das weiß und sie herausfiltern kann. Aber man sollte ehrlichgesagt auch Zahlen nicht als Strings speichern. Aber das ist nun mal das Thema dieses Threads.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TStringlist sortieren

Beitrag von Mathias »

Aber man sollte ehrlichgesagt auch Zahlen nicht als Strings speichern. Aber das ist nun mal das Thema dieses Threads.

Das kommt mehr von als man denkt, ein Beispiel, CD-Titel.

Code: Alles auswählen

01 - Erstes Lied
02 - zweites Lied
03 - etc.

Hier kenne leider ein sehr schlechtes Beispiel, Kodi und UPnP, die habe nicht erkannt, das die 0 vor 1 kommt. :evil:
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TStringlist sortieren

Beitrag von wp_xyz »

Ich verstehe nicht, was das Problem ist: CustomSort bedeutet Handarbeit - in diesem Fall würde ich in der Vergleichsroutine die Strings von links nach rechts durchlaufen bis die erste Nicht-Ziffer kommt, den Ziffernteil herauskopieren, in eine Zahl umwandeln und CompareValue aufrufen. Eine allgemeine Lösung gibt es nicht, der Programmierer muss schon wissen, wie er die Zahlen aus den Strings holen soll.

Antworten