Sự nhầm lẫn trong thứ tự sắp xếp tự nhiên

Hầu hết các trình quản lý tệp đồ họa không sắp xếp theo thứ tự từ điển một cách nghiêm ngặt, mà sử dụng phương pháp sắp xếp "tự nhiên". Các khối số trong tên được hiểu là số - khối số lớn hơn sẽ được ưu tiên, ngay cả khi điều ngược lại đúng theo thứ tự bảng chữ cái. Ý tưởng đằng sau phương pháp sắp xếp tự nhiên: Điều mọi người thường muốn là "9 trước 10", "Chương 2 trước Chương 10" - mà không cần phải thêm số 0 ở đầu.


Các cặp tệp sau đây được sắp xếp tự nhiên theo thứ tự tăng dần như sau:

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

Thật đáng kinh ngạc nhưng có thể giải thích được: Chữ số đầu tiên \(9\) nhỏ hơn khối chữ số đầu tiên \(950\) .

  • IMG_12113419_90.jpg
  • IMG_0554363070_90.jpg

Số \(12113419\) nhỏ hơn \(554363070\) (số \(0\) ở đầu đã bị xóa).

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

Các số được so sánh là \(0\) , \(2\) , \(3\) , \(10\) , \(12\) – dấu “-” không được coi là một phần của số.

Ngay cả "theo bảng chữ cái" cũng không hoàn toàn rõ ràng: Việc viết hoa, dấu ngoặc kép như ä (tiếng Đức), hoặc các chữ cái nhiều ký tự như ch (tiếng Séc) dẫn đến các biến thể hợp lệ. Do đó, "hoàn toàn theo bảng chữ cái" phụ thuộc vào ngữ cảnh. Windows Explorer triển khai điều này trong hàm StrCmpLogicalW . Mặc dù mã nguồn của nó (shlwapi.dll) là độc quyền và không công khai, nhưng vẫn có các bản triển khai lại, ví dụ, từ 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 và các công cụ khác hiển thị hành vi sắp xếp tương tự. Các công cụ CLI như lsfind Tuy nhiên, chúng sắp xếp khác với trình quản lý tệp GUI. Ngữ nghĩa nằm ở tên tệp, không phải ở API. Nếu bạn muốn kết quả không có gì bất ngờ, hãy xác định các quy ước: dấu phân cách nhất quán, số đệm và xử lý đơn vị rõ ràng. Khi đó, "bảng chữ cái" sẽ lại trở nên dễ đoán.

Trở lại