Confuzie în ordinea naturală de sortare

Majoritatea managerilor de fișiere grafice nu sortează strict lexicografic, ci mai degrabă folosind „sortarea naturală”. Blocurile de numere din nume sunt interpretate ca numere - blocul mai mare de numere câștigă, chiar dacă opusul ar ieși în termeni pur alfabetici. Ideea din spatele sortării naturale: ceea ce își doresc oamenii este „9 înainte de 10”, „Capitolul 2 înainte de capitolul 10”, fără a fi nevoie să adauge zerouri de început.


Următoarele perechi de fișiere sunt sortate în mod natural în ordine crescătoare, după cum urmează:

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

Surprinzător, dar explicabil: primul bloc de cifre \(9\) este mai mic decât primul bloc de cifre \(950\) .

  • IMG_12113419_90.jpg
  • IMG_0554363070_90.jpg

Numărul \(12113419\) este mai mic decât \(554363070\) ( \(0\) ul inițial este eliminat).

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

Numerele comparate sunt \(0\) , \(2\) , \(3\) , \(10\) , \(12\) – „-” nu este considerat parte a numărului.

Chiar și „alfabetic” nu este global lipsit de ambiguitate: majusculele, umlautele precum ä (germană) sau literele cu mai multe caractere precum ch (cehă) duc la variante legitime. Prin urmare, „pur alfabetic” depinde de context. Windows Explorer implementează acest lucru în funcția StrCmpLogicalW . Deși codul sursă (shlwapi.dll) este proprietar și nu public, există reimplementări, de exemplu, de la 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 și servicii similare prezintă un comportament de sortare similar. Instrumente CLI precum... ls și find sortați diferit față de managerii de fișiere GUI. Semantica este în numele fișierelor, nu în API. Dacă doriți rezultate fără surprize, definiți convenții: separatori consecvenți, numere căptușite și o manipulare clară a unităților. Apoi „alfabetic” devine din nou previzibil.

Înapoi