الارتباك في ترتيب الفرز الطبيعي

معظم مديري الملفات الرسومية لا يفرزون الملفات معجميًا بحتًا، بل يستخدمون الفرز "الطبيعي". تُفسَّر كتل الأرقام في الاسم على أنها أرقام، وتفوز الكتلة الأكبر، حتى لو كان العكس صحيحًا أبجديًا. الفكرة وراء الفرز الطبيعي هي أن ما يريده المستخدمون عادةً هو "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 (التشيكية) تؤدي إلى صيغٍ صحيحة. لذا، فإن "الأبجدية البحتة" تعتمد على السياق. يُطبّق مستكشف Windows هذا في دالة 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;
}

تُظهر أدوات Google Drive وOneDrive وKDE وغيرها سلوك فرز مشابهًا. أدوات سطر الأوامر مثل ls و find ومع ذلك، فهي تُرتِّب بطريقة مختلفة عن مديري الملفات بواجهة المستخدم الرسومية. الدلالات موجودة في أسماء الملفات، وليس في واجهة برمجة التطبيقات. إذا كنت ترغب في نتائج خالية من المفاجآت، فحدد قواعد: فواصل متسقة، وأرقام مبطنة، ومعالجة واضحة للوحدات. عندها يصبح الترتيب الأبجدي متوقعًا مرة أخرى.

عودة