كيف يمكنني جعل TStringList يقوم بالفرز بشكل مختلف في دلفي

StackOverflow https://stackoverflow.com/questions/2175066

سؤال

لدي قائمة TStringList بسيطة.أقوم بإجراء TStringList.Sort عليه.

ثم لاحظت أن الشرطة السفلية "_" يتم فرزها قبل الحرف الكبير "A".كان هذا على النقيض من حزمة الطرف الثالث التي كانت تقوم بفرز النص نفسه وفرزه _ بعد A.

وفقًا لمجموعة أحرف ANSI، فإن A-Z هي الأحرف من 65 إلى 90 و_ هي 95.لذلك يبدو أن حزمة الطرف الثالث تستخدم هذا الترتيب وأن TStringList.Sort لا يستخدمه.

لقد قمت بالتعمق في أعماق TStringList.Sort ويتم فرزها باستخدام AnsiCompareStr (حساس لحالة الأحرف) أو AnsiCompareText (غير حساس لحالة الأحرف).لقد جربت ذلك في كلا الاتجاهين، حيث قمت بتعيين قيمة CaseSensitive الخاصة بـ StringList على "صحيح" ثم "خطأ".ولكن في كلتا الحالتين، يتم فرز "_" أولاً.

لا أستطيع أن أتخيل أن هذا خطأ في TStringList.لذلك لا بد أن يكون هناك شيء آخر هنا لا أراه.ماذا يمكن أن يكون؟

ما أريد معرفته حقًا هو كيف يمكنني ترتيب TStringList الخاص بي بحيث يكون بنفس ترتيب الحزمة الأخرى.

كمرجع، أنا أستخدم دلفي 2009 وأستخدم سلاسل Unicode في برنامجي.


لذا فإن الإجابة النهائية هنا هي تجاوز مقارنة Ansi بما تريد (على سبيل المثاليقارن غير ansi) على النحو التالي:

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;
هل كانت مفيدة؟

المحلول

تحديد "بشكل صحيح".
i18n الفرز يعتمد تماما على موقعك.
لذلك أنا أتفق تماما مع السلطة الفلسطينية أن هذا ليس خطأ: الافتراضي فرز يعمل السلوك على النحو المصمم للسماح لـ I18N بالعمل بشكل صحيح.

يحب جيري يذكر ، tstringlist.sort الاستخدامات Ansicomparestr و AnsicomParetext (سأشرح في بضعة أسطر كيف يفعل ذلك).

لكن: قائمة tstringlist مرنة ، تحتوي على فرز, الجمارك و المقارنة, ، أي شيء افتراضي (حتى تتمكن من تجاوزها في فصل سليل)
علاوة على ذلك ، عندما تتصل الجمارك, ، يمكنك توصيل خاص بك قارن وظيفة.

في هذه الإجابة قارن الوظيفة التي تفعل ما تريد:

  • حساسية الموضوع
  • عدم استخدام أي لغة
  • فقط قارن القيمة الترتيبية لأحرف الأوتار

الجمارك يتم تعريفه على أنه:

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

بشكل افتراضي ، فرز الطريقة لها تطبيق بسيط للغاية ، ويمرر افتراضيًا قارن وظيفة تسمى StringListComparestrings:

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

لذا ، إذا حددت خاصتك tstringlistsortcompare متناسق قارن الطريقة ، ثم يمكنك تحديد الفرز الخاص بك.
يتم تعريف tstringlistsortcompare على أنها وظيفة عالمية تأخذ قائمة tstringlist وفهرستان يشيران إلى العناصر التي تريد مقارنتها:

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

يمكنك استخدام ال StringListComparestrings كمبدأ توجيهي لتنفيذ بنفسك:

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

لذلك ، بشكل افتراضي tstringlist.sort defers to tlist.comparestrings:

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

التي تستخدم بعد ذلك وظيفة ويندوز ويندوز ويندوز ويندوز المقارنة مع لغة المستخدم الافتراضية 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;

وأخيرا، فإن قارن وظيفة تحتاجها. مرة أخرى القيود:

  • حساسية الموضوع
  • عدم استخدام أي لغة
  • فقط قارن القيمة الترتيبية لأحرف الأوتار

هذا هو الرمز:

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 ليست مغلقة ، عكس ذلك تمامًا: غالبًا ما تكون بنية مرنة حقًا.
غالبًا ما يكون هناك القليل من الحفر لمعرفة أين يمكنك ربط هذه المرونة.

-جيرون

نصائح أخرى

AnsicomParestr / AnsicomParetext يأخذ أكثر من رقم الشخصية في الاعتبار. يأخذون موقع المستخدمين في الاعتبار ، لذا فإن "E" سيتم فرزها مع "é" ، "ê" إلخ.

لجعله فرزه بترتيب ASCII ، استخدم وظيفة مقارنة مخصصة كما هو موضح هنا

AnsiCompareStr (CompareString with LOCALE_USER_DEFAULT) به خطأ، لأنه يحصل على أحرف ذات علامات ترقيم متساوية:

e1 é1 e2 é2

الترتيب الصحيح هو (على سبيل المثال للتشيكية):

E1 E2 é1 é2

هل يعرف أحد كيفية تجنب هذا الخطأ في الطلب؟


11.2.2010:ويجب أن أعتذر عن أن السلوك الموصوف يتوافق تمامًا مع القواعد اللغوية.على الرغم من أنني أعتقد أنه أمر سخيف و"سيئ" إلا أنه ليس خطأ في وظيفة API.

يستخدم Explorer في نظام التشغيل Windows XP ما يسمى بالترتيب البديهي لأسماء الملفات والذي يعطي نتائج أفضل ولكن لا يمكن استخدامه برمجيًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top