مقاله فنی

مقایسه متن در HotXLS: ترتیب word sort اکسل در دلفی

HotXLS Delphi Component از v2.384.67 دو مقدار متنی را همان‌طور مقایسه می‌کند که Excel 16 انجام می‌دهد: بدون حساسیت به بزرگی و کوچکی حروف، با ترتیب word sort مربوط به locale کاربر Windows، همان چیزی که CompareStringW با فلگ NORM_IGNORECASE برمی‌گرداند. خط تیره و آپاستروف در گذر اول نادیده گرفته می‌شوند و فقط تساوی را می‌شکنند، پس ="a-b">"ab" برابر TRUE است، در حالی که بقیه علائم نگارشی قبل از ارقام و حروف مرتب می‌شوند، پس ="a~b"<"ab" هم برابر TRUE است. همین ترتیب حالا عملگرهای مقایسه، معیارهای > / <، مرتب‌سازی محدوده و VLOOKUP را هدایت می‌کند

هیچ‌کس باگ‌ای با عنوان «ناهمخوانی collation» ثبت نمی‌کند. گزارش‌ها می‌گویند COUNTIF(A:A,">M") روی سرور دو سطر بیشتر از Excel می‌شمارد، یا لیست قیمتی که سرویس گزارش‌ساز مرتب کرده X-100 را جایی می‌گذارد که Excel نمی‌گذارد، یا VLOOKUP("ABC",...) برمی‌گرداند #N/A در حالی که ستون به‌وضوح abc دارد. هر سه از یک سؤال می‌آیند: وقتی هر دو عملوند متن‌اند، کدام کوچک‌تر است؟ Excel جواب دقیقی دارد، آن جواب چیزی نیست که بیشتر کدهای Delphi می‌دهند، و HotXLS قبل از v2.384.67 بسته به اینکه کدام مسیر کد سؤال می‌پرسید سه جواب متفاوت می‌داد

Excel برای مقایسه دو رشته متنی از چه قاعده‌ای استفاده می‌کند؟

Excel متن را با word sort مربوط به locale کاربر مقایسه می‌کند و بزرگی و کوچکی حروف را نادیده می‌گیرد. word sort همان collation پیش‌فرض توابع مقایسه NLS در Windows است: حروف به ترتیب زبانی‌شان با هم مقایسه می‌شوند نه به کدپوینت‌شان، حروف دارای اکسان کنار حرف پایه‌شان می‌نشینند، و دو کاراکتر رفتار خاص می‌گیرند. خط تیره - و آپاستروف ' در گذر اول نادیده گرفته می‌شوند، پس co-op و coop کنار هم فرود می‌آیند، و فقط وقتی بقیه رشته‌ها مساوی شوند حضورشان ترتیب را تصمیم می‌گیرد. هر علامت نگارشی دیگر مؤثر است و قبل از ارقام مرتب می‌شود، و ارقام قبل از حروف

جدول نشان می‌دهد این یعنی چه در عمل، کنار دو مقایسه‌ای که یک توسعه‌دهنده Delphi به احتمال زیاد سراغش می‌رود. ستون Excel حکم‌هایی است که Excel 16 برای IF(A<B,...) برگردانده، و HotXLS از v2.384.67 همان‌ها را بازتولید می‌کند

A در برابر BExcel 16 / HotXLSCompareStr (ordinal)CompareText
"a-b" vs "ab"بزرگ‌ترکوچک‌ترکوچک‌تر
"a'b" vs "ab"بزرگ‌ترکوچک‌ترکوچک‌تر
"a~b" vs "ab"کوچک‌تربزرگ‌تربزرگ‌تر
"a_b" vs "ab"کوچک‌ترکوچک‌تربزرگ‌تر
"ab" vs "AB"مساویبزرگ‌ترمساوی
"é" vs "f"کوچک‌تربزرگ‌تربزرگ‌تر
"Z" vs "f"بزرگ‌ترکوچک‌تربزرگ‌تر

دو نتیجه به‌راحتی از چشم می‌افتد. اول، نقش تساوی‌شکن خط تیره یعنی ="a-b"="ab" برابر FALSE است: دو رشته در ترتیب همسایه‌های نزدیک‌اند، اما مساوی نیستند. دوم، تساوی بزرگی حروف را کلاً نادیده می‌گیرد، پس ab و AB و Ab تا وقتی مقایسه در میان است همه یک کلیدند. مرتب کردن 20 کلمه تست با Range.Sort خود Excel این ترتیب را می‌دهد: a b، a.b، a_b، a~b، a0، a1b، ab / AB / Ab، ab-، a'b، a-b، -ab، ab1، abc، b، e، é، f، Z؛ داخل گروه ab، جای کاراکتر نادیده‌گرفته‌شده است که تصمیم می‌گیرد

نمودار word sort در HotXLS که هر 20 کلمه تست را رتبه‌بندی می‌کند: از a b و a.b و a_b و a~b تا a0 و a1b، بعد گروه ab با AB و Ab، واریانت‌های خط تیره و آپاستروف مثل a-b و a'b، تا abc و b و e و e با اکسان و f و Z، و نشان می‌دهد علائم نگارشی قبل از ارقام و ارقام قبل از حروف می‌آیند و بزرگی حروف نادیده گرفته می‌شود
علائم نگارشی و فاصله قبل از ارقام مرتب می‌شوند و ارقام قبل از حروف، بزرگی حروف جمع می‌شود، و خط تیره با آپاستروف فقط تساوی را می‌شکنند؛ برای همین a-b کنار ab فرود می‌آید اما همچنان بزرگ‌تر مقایسه می‌شود

ترتیب متنی Excel چطور دقیق مشخص شد؟

ترتیب متنی Excel با اندازه‌گیری شناسایی شد نه با مستندات، چون مستندات Excel نامی از collation نمی‌برد. تست 4000 جفت رشته تصادفی از علائم نگارشی ASCII و ارقام و هر دو حالت بزرگی حروف و فاصله‌ها و é و ß و ä و کاراکترهای چینی و فرم‌های full-width و فاصله غیرشکن تولید کرد، با طول‌های 0 تا 4 و نصف جفت‌ها به‌شکل near-miss های همدیگر. Excel 16 برای هر جفت IF(A<B,-1,IF(A=B,0,1)) را ارزیابی کرد، و حکم‌ها با API مقایسه Windows با مجموعه فلگ‌های مختلف تطبیق داده شد

  • فقط NORM_IGNORECASE (word sort پیش‌فرض، locale کاربر): هیچ ناهمخوانی واقعی‌ای نبود. تنها 7 تفاوت سلول‌هایی بودند که کل محتوایشان ' بود، که Excel آن را به‌عنوان کاراکتر پیشوند متن مصرف می‌کند، پس خطای نمونه‌برداری بودند نه تفاوت collation
  • NORM_IGNORECASE با SORT_STRINGSORT: تعداد 41 ناهمخوانی. string sort خط تیره و آپاستروف را علامت معمولی می‌گیرد، و دقیقاً همین رفتاری است که Excel ندارد
  • اضافه کردن NORM_IGNOREWIDTH: به شکل دیگری غلط بود، چون فرم full-width و half-width یک حرف را مساوی می‌گیرد و Excel آن‌ها را جدا نگه می‌دارد

یک چک دوم دستچین‌شده، همه 190 جفت ساخته‌شده از 20 کلمه پرچالش و نتیجه Range.Sort خود Excel روی همان ستون را مقایسه کرد. هر دو با word sort ساده یعنی NORM_IGNORECASE موافق بودند، و همان 190 حکم به‌علاوه ترتیب مرتب‌شده حالا بخشی از regression suite مربوط به HotXLS‌اند، و هم از موتور کلاسیک یعنی TXLSWorkbook می‌گذرند هم از موتور بومی XLSX یعنی TXLSXWorkbook

چرا CompareText و مقایسه ordinal جواب اشتباه می‌دهند؟

CompareText و مقایسه ordinal به این دلیل ترتیب Excel را غلط درمی‌آورند که UTF-16 code unit ها را مقایسه می‌کنند، و ترتیب کدپوینت علائم نگارشی را در جای‌های تصادفی نسبت به حروف می‌گذارد. خط تیره U+002D و آپاستروف U+0027 هر دو زیر همه حروف‌اند، پس مقایسه ordinal می‌گوید "a-b" کوچک‌تر از "ab" است به‌جای اینکه خط تیره را تساوی‌شکن بداند. علامت مد U+007E بالای همه حروف است، پس "a~b" بزرگ‌تر درمی‌آید، برعکس Excel. ‏CompareText در RTL مربوط به Delphi فقط a..z را به حروف بزرگ می‌برد و بعد code unit ها را مقایسه می‌کند، که یک اعوجاج دوم اضافه می‌کند: آندرلاین U+005F بین حروف بزرگ و کوچک نشسته، پس آوردن به حروف بزرگ "a_b" را از زیر "ab" می‌برد بالایش. هیچ‌کدام از این دو تابع نمی‌دانند که é باید بین e و f بنشیند

نمودار مقایسه HotXLS که ترتیب کدپوینت را با word sort اکسل تضاد می‌دهد: مقایسه ordinal آپاستروف و خط تیره و آندرلاین را روی 0x27 و 0x2D و 0x5F دور حروف می‌گذارد پس a-b در برابر ab کوچک‌تر درمی‌آید، درحالی‌که word sort علائم نگارشی را قبل از ارقام و حروف می‌برد و فقط خط تیره و آپاستروف را تساوی‌شکن می‌داند
کدپوینت‌ها علائم نگارشی را دور حروف پخش می‌کنند، پس مقایسه‌های ordinal و تاشده-ASCII حکم‌ها را برعکس می‌کنند؛ word sort علائم نگارشی را جلوی ارقام می‌برد و خط تیره و آپاستروف را به تساوی‌شکن تنزل می‌دهد

ابزارهای همیشگی Delphi در دو طرف این خط افتاده‌اند:

  • CompareStr و عملگر < روی رشته و TComparer<string>.Default (که CompareStr را صدا می‌زند) ordinal و حساس به بزرگی حروف‌اند، پس TArray.Sort<string> بدون comparer گذاشتن Z را قبل از f می‌گذارد
  • CompareText و SameText بعد از تاشدن ASCII-فقط بزرگی حروف، ordinal هستند
  • AnsiCompareText و WideCompareText در RTL مربوط به Delphi روی Windows صدا می‌زنند CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, ...)، همان فراخوانی که با Excel جور است. یک TStringList مرتب‌شده با تنظیمات پیش‌فرضش (‏UseLocale برابر True و CaseSensitive برابر False) از AnsiCompareText می‌گذرد و پس با Excel هم موافق است
  • روی targetهای POSIX، RTL مربوط به Delphi مسیر AnsiCompareText را به یک collator از ICU می‌فرستد که الگوریتم دیگری با قواعد نگارشی متفاوت است، و AnsiCompareText در Free Pascal روی Windows بعد از تبدیل به code page ANSI صدا می‌زند CompareStringA را، که هر کاراکتری را آن صفحه نتواند نمایندگی کند از دست می‌دهد

پس توابع RTL آگاه-از-locale روی Windows به لطف پیاده‌سازی درست‌اند نه به لطف قرارداد، و کدی که ترتیب Excel را لازم دارد بهتر است خودش فراخوانی API را صریح انجام دهد. HotXLS هم در درون همین ترکیب را داشت. عملگرهای مقایسه هر دو رشته را به حروف بزرگ می‌بردند و کدپوینت‌ها را مقایسه می‌کردند، شاخه‌های > / < توابع معیار از مقایسه Variant حساس-به-حروف خود Delphi استفاده می‌کردند، و VLOOKUP / HLOOKUP هم متن را با همان مقایسه Variant حساس-به-حروف مچ می‌کردند، و برای همین بود که VLOOKUP("ABC",A1:A20,1,FALSE) نمی‌توانست abc را پیدا کند. مرتب‌سازی محدوده از قبل WideCompareText را داشت. سه مسیر، سه ترتیب

در HotXLS نسخه v2.384.67 چه چیزی عوض شد؟

از v2.384.67 مقایسه‌های متن-با-متن در مسیرهای محاسبه و مرتب‌سازی HotXLS از یک تابع می‌گذرند، XlsCompareText در lxStandard.pas، که صدا می‌زند CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, ...) و CSTR_EQUAL را کم می‌کند. فراخواننده‌ها شش عملگر مقایسه‌اند، مقایسه‌های المان به المان در فرمول‌های آرایه‌ای، شاخه‌های > و < و >= و <= معیارهای سبک COUNTIF و توابع دیتابیس، ‏VLOOKUP و HLOOKUP (دقیق و تقریبی)، helperهای ترتیب پشت توابع آرایه پویا و XLOOKUP / XMATCH، و مرتب‌سازی محدوده در هر دو موتور. هدایت مرتب‌سازی محدوده از همان تابع تضمین می‌کند ترتیب sort و ترتیب مقایسه دیگر از هم فاصله نگیرند، که اهمیت دارد چون VLOOKUP تقریبی روی متن فقط وقتی معنا دارد که ستون با همان ترتیبی مرتب شده باشد که lookup در آن مقایسه می‌کند

نمودار مسیریابی HotXLS که همه مسیرهای مقایسه متن را نشان می‌دهد: از شش عملگر مقایسه و معیارهای سبک COUNTIF تا VLOOKUP و HLOOKUP و XLOOKUP و مرتب‌سازی محدوده در هر دو موتور، همه به XlsCompareText همگرا می‌شوند که CompareStringW را با LOCALE_USER_DEFAULT و NORM_IGNORECASE صدا می‌زند و 1 و 2 و 3 را به -1 و 0 و 1 می‌برد
عملگرها و معیارها و lookupها و مرتب‌سازی یک تابع مشترک دارند، پس ترتیبی که Excel می‌بیند و ترتیبی که HotXLS با آن sort می‌کند دیگر از هم فاصله نمی‌گیرند؛ API مقدار 1 یا 2 یا 3 برمی‌گرداند و صفر یعنی شکست، نه کوچک‌تر
uses
  System.Variants, lxHandleX;

var
  Book: TXLSXWorkbook;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Sheets.Add('Data');  // Calculate روی شیت فعال ارزیابی می‌کند
    Writeln(VarToStr(Book.Calculate('="a-b">"ab"')));   // True: خط تیره فقط تساوی را می‌شکند
    Writeln(VarToStr(Book.Calculate('="a-b"="ab"')));   // False: تساوی شکسته شد، مساوی نیستند
    Writeln(VarToStr(Book.Calculate('="a~b"<"ab"')));   // True: علائم نگارشی اول
    Writeln(VarToStr(Book.Calculate('="ABC"="abc"')));  // True: بزرگی حروف نادیده گرفته می‌شود
  finally
    Book.Free;
  end;
end;

مقایسه‌های بین-نوعی قاعده جداگانه‌ای دارند و تغییری نکردند: هر عددی زیر هر مقدار متنی است و هر مقدار متنی زیر هر boolean، همان‌طور که در مقاله زنجیره‌های مقایسه، عملوندهای خالی و SUMIF توضیح داده شده. word sort فقط وقتی اعمال می‌شود که هر دو عملوند متن باشند. مچ کردن wildcard هم جدا است: معیاری مثل "a*" یا "=ab" یک pattern یا تست تساوی است، که در راهنمای wildcard های Excel در COUNTIF و MATCH و DSUM پوشش داده شده، و collation ای که اینجا بحث شد فقط عملگرهای ترتیب را تصمیم می‌گیرد

مثال بعدی 20 کلمه تست را در یک ستون load می‌کند، با TXLSXWorksheet.SortRange مرتبش می‌کند، و یک شمارش معیار و یک lookup را چک می‌کند. شمارش‌ها همان‌هایی‌اند که Excel 16 برای همان ستون برگردانده

const
  Words: array [0..19] of string = ('ab', 'a-b', 'a~b', 'a_b', 'AB', 'a b',
    'ab1', 'ab-', '-ab', 'abc', 'a''b', 'Ab', 'b', 'a.b', 'a1b', 'a0',
    #$00E9, 'e', 'f', 'Z');
var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  i: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Sheet := Book.Sheets.Add('Words');
    for i := 0 to High(Words) do
      Sheet.Cells[i + 1, 1].Value := WideString(Words[i]);

    // Excel 16 روی همان ستون: 11، 11، 14
    Writeln(VarToStr(Book.Calculate('=COUNTIF(A1:A20,">ab")')));
    Writeln(VarToStr(Book.Calculate('=COUNTIF(A1:A20,"<a-b")')));
    Writeln(VarToStr(Book.Calculate('=COUNTIF(A1:A20,">=AB")')));

    // قبل از v2.384.67 برابر #N/A بود: lookup حساس به بزرگی حروف مقایسه می‌کرد
    Sheet.Cells[1, 3].Formula := '=VLOOKUP("ABC",A1:A20,1,FALSE)';
    Book.Recalculate;
    Writeln(VarToStr(Sheet.Cells[1, 3].Value));                // abc

    // یک ستون کلید، صعودی: a b، a.b، a_b، a~b، a0، a1b، ab، AB، Ab، ...
    Sheet.SortRange(1, 1, 20, 1, [1], [False]);
    for i := 1 to 20 do
      Writeln(VarToStr(Sheet.Cells[i, 1].Value));
  finally
    Book.Free;
  end;
end;

TXLSXWorksheet.SortRange از یک merge sort پایدار استفاده می‌کند، پس ab و AB و Ab که مساوی مقایسه می‌شوند ترتیب نسبی قبل از sort را نگه می‌دارند. سلول‌های خالی در هر دو جهت به انتها می‌روند، همان‌طور که در Excel

چطور در کد Delphi خودم به ترتیب sort اکسل برسم؟

برای رسیدن به ترتیب متنی Excel در کد خودتان، CompareStringW را با LOCALE_USER_DEFAULT و NORM_IGNORECASE صدا بزنید و SORT_STRINGSORT یا NORM_IGNOREWIDTH اضافه نکنید. مقدار برگشتی یک نتیجه مقایسه علامت‌دار نیست: API برمی‌گرداند CSTR_LESS_THAN (1) یا CSTR_EQUAL (2) یا CSTR_GREATER_THAN (3)، و 0 وقتی فراخوانی شکست بخورد. برای رسیدن به قرارداد همیشگی منفی/صفر/مثبت 2 کم کنید، و اول 0 را تست کنید، چون شکستی که اشتباهی نتیجه گرفته شود می‌شود -2، یک «کوچک‌تر» بی‌صدا

uses
  Winapi.Windows, System.SysUtils, System.Generics.Defaults,
  System.Generics.Collections;

// ترتیب متنی Excel: word sort با locale کاربر، بدون حساسیت به بزرگی حروف
function ExcelCompareText(const A, B: string): Integer;
var
  R: Integer;
begin
  R := CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
    PWideChar(A), Length(A), PWideChar(B), Length(B));
  if R = 0 then
    RaiseLastOSError;          // صفر یعنی شکست، نه نتیجه مقایسه
  Result := R - CSTR_EQUAL;    // 1/2/3 می‌شوند -1/0/1
end;

var
  Keys: TArray<string>;
begin
  Keys := ['abc', 'a-b', 'AB', 'a~b', '-ab', 'ab'];
  TArray.Sort<string>(Keys, TComparer<string>.Construct(
    function(const L, R: string): Integer
    begin
      Result := ExcelCompareText(L, R);
    end));
  // a~b، ab / AB (مساوی، به هر ترتیبی)، a-b، -ab، abc
end;

TArray.Sort پایدار نیست، پس کلیدهایی که مساوی مقایسه می‌شوند مثل ab و AB ممکن است به هر ترتیبی دربیایند؛ اگر ترتیب اصلی کلیدهای مساوی مهم است، یک آرایه اندیس را با موقعیت اصلی به‌عنوان کلید ثانویه مرتب کنید. حالت برعکسش هم پیش می‌آید: گاهی یک ستون نباید از ترتیب Excel پیروی کند، مثلاً شماره قطعه‌ها که X-100 و X100 کدهای متمایزند و باید بر اساس کدپوینت مرتب شوند. ‏TXLSXWorksheet.SortRange یک overload دارد که یک TXLSSortCompareEvent می‌گیرد، متدی با امضا function(const Left, Right: Variant): Integer of object، و به‌جای مقایسه داخلی از آن استفاده می‌کند

uses
  System.SysUtils, System.Variants, lxStandard, lxHandleX;

type
  TPartNumberOrder = class
    function Compare(const Left, Right: Variant): Integer;
  end;

function TPartNumberOrder.Compare(const Left, Right: Variant): Integer;
begin
  // یک comparer سفارشی سلول‌های خالی را هم می‌گیرد (به‌شکل Null): خودتان جایشان را بدهید
  if VarIsNull(Left) or VarIsNull(Right) then
    Exit(Ord(VarIsNull(Left)) - Ord(VarIsNull(Right)));
  Result := CompareStr(VarToStr(Left), VarToStr(Right));   // ordinal، حساس به بزرگی حروف
end;

var
  Sheet: TXLSXWorksheet;   // یک شیت پرشده، سطرهای 2 تا 501، ستون‌های A تا D
  Order: TPartNumberOrder;
begin
  // ...
  Order := TPartNumberOrder.Create;
  try
    // کلید بر ستون A، صعودی
    Sheet.SortRange(2, 1, 501, 4, [1], [False], xlsSortByRows,
      xlsSortExcelLike, Order.Compare);
  finally
    Order.Free;
  end;
end;

وقتی comparer سفارشی داده می‌شود، HotXLS مدیریت خالی خودش را کنار می‌گذارد و مقدارهای خام کلید را می‌فرستد، پس comparer باید با Null کنار بیاید. برای کلید نزولی HotXLS هر چیزی که comparer برمی‌گرداند منفی می‌کند، که خالی‌ها را هم می‌برد بالای لیست مگر اینکه comparer خودش حسابشان کند. در نظر بگیرید که ستونی که این‌طور مرتب شده دیگر در ترتیبی نیست که VLOOKUP تقریبی Excel یا XLOOKUP مبتنی بر جست‌وجوی دودویی انتظارش را دارد؛ دام‌های این مدها روی داده مرتب‌شده به ترتیبی دیگر در راهنمای مدهای جست‌وجوی دودویی XLOOKUP و XMATCH پوشش داده شده

چرا ممکن است همان workbook روی دستگاه دیگری جور دیگری مرتب شود؟

همان workbook می‌تواند روی دستگاه دیگری جور دیگری مرتب شود، چون ترتیب متنی Excel به locale کاربر Windows وابسته است و HotXLS عمداً همین وابستگی را دنبال می‌کند. word sort به زبان وابسته است: collation سوئدی مثلاً ä را بعد از z می‌گذارد، در حالی که انگلیسی و آلمانی کنار a نگهش می‌دارند. Excel این را از locale ای که زیرش اجرا می‌شود به ارث می‌برد، پس workbookی که همکار استکهلمی دوباره محاسبه کند می‌تواند COUNTIF(...,">y") متفاوتی از همان فایل روی دسکتاپی در شیکاگو برگرداند. HotXLS مقدار LOCALE_USER_DEFAULT را پاس می‌کند تا نتایجش روی همان دستگاه با Excel برابر باشد؛ هر locale ثابتی باعث می‌شد HotXLS روی هر دستگاهی با تنظیم متفاوت با Excel ناهمخوان شود

سه نتیجه عملی برای تولید سمت-سرور دنبال دارد:

  • locale ای که اهمیت دارد مالِ حسابی است که پروسه زیرش اجرا می‌شود. یک Windows service یا application pool مربوط به IIS ممکن است فرمت منطقه‌ای متفاوتی از دسکتاپ توسعه‌دهنده داشته باشد، پس نتیجه‌هایی که در IDE دیده‌اید خودکار همان چیزی نیست که production محاسبه می‌کند
  • نتیجه‌های فرمول cache‌شده‌ای که داخل فایل نوشته می‌شوند locale دستگاه مولد را منعکس می‌کنند. Excel با locale خودش دوباره محاسبه می‌کند، پس یک مقدار می‌تواند وقتی فایل جای دیگری باز و دوباره محاسبه می‌شود عوض شود؛ این رفتار Excel است نه artifact مربوط به HotXLS
  • localeها بیشتر روی حروف دارای اکسان اختلاف دارند، روی ترکیب‌های حرفی که بعضی زبان‌ها یک حرف حساب می‌کنند، و روی scriptهای غیر-لاتین، پس داده تستی محدود به کلمات ساده انگلیسی مشکل را لو نمی‌دهد

مرز پلتفرم ساده است. HotXLS یک کتابخانه Windows است، ساخته‌شده برای Win32 و Win64 با Delphi و C++Builder و برای targetهای win32 / win64 با Lazarus و Free Pascal، و همه این buildها همان CompareStringW را صدا می‌زنند. مسیر collation جداگانه‌ای برای غیر-Windows وجود ندارد. تنها fallback برای فراخوانی ناموفق API است: اگر CompareStringW صفر برگرداند، ‏XlsCompareText رشته‌های به-حروف-بزرگ‌شده را بر اساس code unit مقایسه می‌کند به‌جای وسط یک محاسبه مجدد exception دادن، که محاسبه را روشن نگه می‌دارد اما دیگر ترتیب Excel را تضمین نمی‌کند

مرجع سریع: مقایسه متن اکسل در HotXLS

  • قاعده: word sort با locale کاربر و NORM_IGNORECASE، بدون SORT_STRINGSORT، بدون NORM_IGNOREWIDTH، در HotXLS از v2.384.67
  • - و ' فقط تساوی را می‌شکنند: ="a-b">"ab" برابر TRUE است و ="a-b"="ab" برابر FALSE
  • بقیه علائم نگارشی قبل از ارقام مرتب می‌شوند و ارقام قبل از حروف: ="a~b"<"ab" و ="a0"<"ab" برابر TRUE هستند
  • بزرگی حروف هرگز مهم نیست: ="ABC"="abc" برابر TRUE است و VLOOKUP("ABC",...) مقدار abc را پیدا می‌کند
  • مسیرهای پوشش‌داده‌شده: عملگرهای مقایسه، مقایسه‌های آرایه، معیارهای > / <، ‏VLOOKUP / HLOOKUP، ترتیب‌دهی آرایه پویا، ‏SortRange در هر دو موتور
  • مشمول این قاعده نیستند: نوع‌های مخلوط (عدد < متن < boolean) و معیارهای wildcard، که قواعد خودشان را دارند
  • در کد Delphi: ‏CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, ...)، صفر را چک کنید، ‏CSTR_EQUAL را کم کنید؛ از CompareText و CompareStr و TComparer<string>.Default پرهیز کنید وقتی نتیجه باید با Excel جور باشد
  • نتیجه‌ها به locale حسابی بستگی دارند که کد را اجرا می‌کند، هم در Excel و هم در HotXLS

کلمات معمولی زیر هر قاعده‌ای یک‌طور مرتب می‌شوند، پس فقط کدهای خط-تیره‌دار و علائم نگارشی و اسم‌های دارای اکسان یک collation غلط را لو می‌دهند. HotXLS حالا روی همه این‌ها جواب Excel را در هر دو موتور XLS و XLSX می‌دهد. جزئیات لایسنس و نسخه‌های پشتیبانی‌شده Delphi و C++Builder و دانلود آزمایشی در صفحه کامپوننت Excel مربوط به HotXLS در Delphi است