2010-02-01 30 views
13

Tôi có một TStringList đơn giản. Tôi làm một TStringList.Sort trên đó.Làm thế nào tôi có thể nhận TStringList để sắp xếp khác nhau trong Delphi

Sau đó, tôi nhận thấy rằng dấu gạch dưới "_" sắp xếp trước chữ hoa "A". Điều này trái ngược với gói của bên thứ ba đang phân loại cùng một văn bản và được sắp xếp _ sau A.

Theo bộ ký tự ANSI, AZ là các ký tự 65 - 90 và _ là 95. Vì vậy, trông giống như bên thứ 3 gói đang sử dụng thứ tự đó và TStringList.Sort không phải là.

Tôi khoan thành ruột của TStringList.Sort và sắp xếp bằng AnsiCompareStr (Phân biệt chữ hoa chữ thường) hoặc AnsiCompareText (Phân biệt chữ hoa chữ thường). Tôi đã thử cả hai cách, đặt giá trị CaseSensitive của StringList thành true và sau đó là false. Nhưng trong cả hai trường hợp, "_" sắp xếp trước.

Tôi không thể tưởng tượng rằng đây là lỗi trong TStringList. Vì vậy, phải có một cái gì đó khác ở đây mà tôi không nhìn thấy. Điều đó có thể là gì?

Điều tôi thực sự cần biết là làm thế nào tôi có thể lấy TStringList để sắp xếp sao cho nó theo thứ tự giống như gói khác.

Để tham khảo, tôi đang sử dụng Delphi 2009 và tôi đang sử dụng chuỗi Unicode trong chương trình của mình.


Vì vậy, câu trả lời chính thức ở đây là để ghi đè lên Ansi so sánh với bất cứ điều gì bạn muốn (ví dụ phi ansi so sánh) như sau:

type 
    TMyStringList = class(TStringList) 
    protected 
    function CompareStrings(const S1, S2: string): Integer; override; 
    end; 

function TMyStringList.CompareStrings(const S1, S2: string): Integer; 
begin 
    if CaseSensitive then 
    Result := CompareStr(S1, S2) 
    else 
    Result := CompareText(S1, S2); 
end; 
+3

Windows cũng sắp xếp '_' trước' A' để TStringlist ít nhất là bao gồm hệ điều hành. –

+2

nhận được kết quả mà bạn không mong đợi, không có nghĩa đó là lỗi. Nó không phải là một lỗi, nó được thiết kế theo cách này để hỗ trợ chính xác của người dùng (hoặc của hệ điều hành thay mặt cho người dùng) lựa chọn thứ tự sắp xếp. –

+0

Bạn đang viết câu hỏi này với giả định rằng có * là * một cách chính xác để sắp xếp các ký tự không phải là chữ cái. Các từ gạch dưới xuất hiện ở đâu trong từ điển của bạn? –

Trả lời

35

Xác định " đúng ".
i18n sắp xếp hoàn toàn tùy thuộc vào ngôn ngữ của bạn.
Vì vậy, tôi hoàn toàn đồng ý với PA rằng đây không phải là lỗi: mặc định Sắp xếp hành vi hoạt động như được thiết kế để cho phép i18n hoạt động bình thường.

Giống như Gerry đề cập, TStringList.Sort sử dụng AnsiCompareStrAnsiCompareText (tôi sẽ giải thích trong một vài dòng như thế nào nó đó).

Nhưng: TStringList là linh hoạt, nó có chứa Sắp xếp, CustomSortCompareStrings, mà tất cả đều là ảo (để bạn có thể ghi đè lên chúng trong một lớp hậu duệ)
Hơn nữa, khi bạn gọi CustomSort, bạn có thể cắm vào chức năng của riêng bạn So sánh chức năng.

Tại các câu trả lời này là một Hãy so sánh chức năng mà những gì bạn muốn:

  • Trường hợp nhạy cảm
  • Không sử dụng bất kỳ locale
  • Chỉ cần so sánh giá trị thứ tự của các nhân vật trong những chuỗi

CustomSort được định nghĩa là:

procedure TStringList.CustomSort(Compare: TStringListSortCompare); 
begin 
    if not Sorted and (FCount > 1) then 
    begin 
    Changing; 
    QuickSort(0, FCount - 1, Compare); 
    Changed; 
    end; 
end; 

Theo mặc định, Sắp xếp phương pháp có một thực hiện rất đơn giản, đi qua một mặc định Hãy so sánh chức năng gọi StringListCompareStrings:

procedure TStringList.Sort; 
begin 
    CustomSort(StringListCompareStrings); 
end; 

Vì vậy, nếu bạn định nghĩa của riêng bạn TStringListSortCompare tương thích So sánh phương pháp, sau đó bạn có thể xác định phân loại của riêng mình.
TStringListSortCompare được định nghĩa là một chức năng toàn cầu lấy TStringList và hai chỉ số tham khảo các mục mà bạn muốn so sánh:

type 
    TStringListSortCompare = function(List: TStringList; Index1, Index2: Integer): Integer; 

Bạn có thể sử dụng StringListCompareStrings như một kim chỉ nam cho việc thực hiện của riêng bạn:

function StringListCompareStrings(List: TStringList; Index1, Index2: Integer): Integer; 
begin 
    Result := List.CompareStrings(List.FList^[Index1].FString, 
           List.FList^[Index2].FString); 
end; 

Vì vậy, theo mặc định, TStringList.Sort sẽ chuyển sang TList.CompareStrings:

function TStringList.CompareStrings(const S1, S2: string): Integer; 
begin 
    if CaseSensitive then 
    Result := AnsiCompareStr(S1, S2) 
    else 
    Result := AnsiCompareText(S1, S2); 
end; 

nào sau đó sử dụng dưới nói dối của Windows hàm API CompareString với người dùng miền địa phương mặc định LOCALE_USER_DEFAULT:

function AnsiCompareStr(const S1, S2: string): Integer; 
begin 
    Result := CompareString(LOCALE_USER_DEFAULT, 0, PChar(S1), Length(S1), 
    PChar(S2), Length(S2)) - 2; 
end; 

function AnsiCompareText(const S1, S2: string): Integer; 
begin 
    Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(S1), 
    Length(S1), PChar(S2), Length(S2)) - 2; 
end; 

Cuối cùng Hãy so sánh chức năng mà bạn cần. Một lần nữa những hạn chế:

  • Trường hợp nhạy cảm
  • Không sử dụng bất kỳ locale
  • Chỉ cần so sánh giá trị thứ tự của các nhân vật trong những chuỗi

này được mã:

function StringListCompareStringsByOrdinalCharacterValue(List: TStringList; Index1, Index2: Integer): Integer; 
var 
    First: string; 
    Second: string; 
begin 
    First := List[Index1]; 
    Second := List[Index2]; 
    if List.CaseSensitive then 
    Result := CompareStr(First, Second) 
    else 
    Result := CompareText(First, Second); 
end; 

Delphi không bị đóng, hoàn toàn ngược lại: thường nó là một kiến ​​trúc thực sự linh hoạt.
Nó thường chỉ là một chút đào để xem nơi bạn có thể móc vào sự linh hoạt đó.

--jeroen

+0

Rất đẹp! Tôi biết về điều này, nhưng đã không nhìn thấy tất cả điều này được mô tả ở một nơi trước đây. –

+0

Đó là lý do tại sao tôi làm cho nó trở thành một cộng đồng wiki :-) –

5

AnsiCompareStr/AnsiCompareText mất nhiều hơn số nhân vật vào tài khoản. Họ đưa những người sử dụng Locale vào tài khoản, vì vậy "e" sẽ sắp xếp cùng với "é", "ê" vv

Để làm cho nó sắp xếp nó theo thứ tự Ascii, sử dụng một tùy chỉnh so sánh chức năng as described here

0

AnsiCompareStr (CompareString với LOCALE_USER_DEFAULT) có lỗi, bởi vì nó được nhân vật với punctation như bằng nhau:

e1 E1 e2 E2

trật tự đúng là (ví dụ cho Cộng hòa Séc):

e1 e2 é1 é2

Có ai biết cách tránh lỗi này khi đặt hàng không?


11.2.2010: Tôi phải xin lỗi hành vi được mô tả hoàn toàn theo các quy tắc ngôn ngữ. Mặc dù tôi nghĩ rằng nó là ngớ ngẩn và "xấu" nó không phải là lỗi trong chức năng API.

Trình khám phá trong Windows XP sử dụng cái gọi là sắp xếp tên tệp trực quan mang lại kết quả tốt hơn nhưng không thể sử dụng theo chương trình.

Các vấn đề liên quan