سردرگمی در ترتیب مرتب‌سازی طبیعی

اکثر مدیران فایل های گرافیکی به طور دقیق واژگانی مرتب سازی نمی کنند، بلکه از «مرتب سازی طبیعی» استفاده می کنند. بلوک های اعداد در نام به عنوان اعداد تفسیر می شوند - بلوک اعداد بزرگتر برنده می شود، حتی اگر عکس آن به صورت کاملاً الفبایی ظاهر شود. ایده پشت مرتب‌سازی طبیعی: چیزی که مردم بیشتر می‌خواهند «9 قبل از 10»، «فصل 2 قبل از فصل 10» است، بدون نیاز به اضافه کردن صفرهای ابتدایی.


جفت فایل‌های زیر به طور طبیعی به ترتیب صعودی به صورت زیر مرتب شده‌اند:

  • build-9e2.log
  • build-950.log

به طرز شگفت انگیزی، اما قابل توضیح: بلوک رقمی اول \(9\) کوچکتر از بلوک رقمی اول \(950\) است.

  • IMG_12113419_90.jpg
  • IMG_0554363070_90.jpg

عدد \(12113419\) کمتر از \(554363070\) است (عدد \(0\) از ابتدای آن حذف شده است).

  • temp_0C.txt
  • temp_2C.txt
  • temp_-3C.txt
  • temp_10C.txt
  • temp_-12C.txt

اعداد مقایسه شده عبارتند از \(0\) ، \(2\) ، \(3\) ، \(10\) ، \(12\) - علامت "-" بخشی از عدد محسوب نمی‌شود.

حتی «الفبایی» هم در سطح جهانی بدون ابهام نیست: حروف بزرگ، حروف ترکیبی مانند ä (آلمانی) یا حروف چند کاراکتری مانند ch (چکی) منجر به انواع مشروع می‌شوند. بنابراین «صرفاً الفبایی» وابسته به متن است. ویندوز اکسپلورر این را در تابع StrCmpLogicalW پیاده‌سازی می‌کند. در حالی که کد منبع آن (shlwapi.dll) اختصاصی است و عمومی نیست، پیاده‌سازی‌های مجددی، به عنوان مثال، از ReactOS وجود دارد.:

{
    TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(comp));
 
    if (!str || !comp)
        return 0;
 
    while (*str)
    {
        if (!*comp)
            return 1;
        else if (*str >= '0' && *str <= '9')
        {
            int str_value, comp_value;
 
            if (*comp < '0' || *comp > '9')
                return -1;
 
            /* Compare the numbers */
            StrToIntExW(str, 0, &str_value);
            StrToIntExW(comp, 0, &comp_value);
 
            if (str_value < comp_value)
                return -1;
            else if (str_value > comp_value)
                return 1;
 
            /* Skip */
            while (*str >= '0' && *str <= '9') str++;
            while (*comp >= '0' && *comp <= '9') comp++;
        }
        else if (*comp >= '0' && *comp <= '9')
            return 1;
        else
        {
            int diff = ChrCmpIW(*str, *comp);
            if (diff > 0)
                return 1;
            else if (diff < 0)
                return -1;
 
            str++;
            comp++;
        }
    }
 
    if (*comp)
      return -1;
 
    return 0;
}

گوگل درایو، وان درایو، کی‌دی‌ای و سرویس‌های مشابه رفتار مرتب‌سازی مشابهی را نشان می‌دهند. ابزارهای رابط خط فرمان (CLI) مانند... ls و find مرتب سازی متفاوت از مدیریت فایل GUI. معنایی در نام فایل ها است، نه در API. اگر می‌خواهید نتایجی بدون غافلگیری داشته باشید، قراردادها را تعریف کنید: جداکننده‌های ثابت، اعداد پرشده و مدیریت واضح واحدها. سپس "الفبایی" دوباره قابل پیش بینی می شود.

بازگشت