Skip to content

sort: locale-based collation is not supported #10314

Description

@sylvestre

sort: locale-based collation is not supported

Component

sort

Description

GNU sort uses locale-based string comparison (collation) when the LC_COLLATE environment variable is set to a non-C locale. This affects the default alphabetical ordering of strings.

In GNU sort, the program checks if the locale is hard.

hard_LC_COLLATE = hard_locale (LC_COLLATE);

When hard_LC_COLLATE is true, GNU sort uses the xmemcoll0 function for string comparison at line 2958.

else if (hard_LC_COLLATE)
  {
    /* xmemcoll0 is a performance enhancement as
       it will not unconditionally write '\0' after the
       passed in buffers, which was seen to give around
       a 3% increase in performance for short lines.  */
    diff = xmemcoll0 (a->text, alen + 1, b->text, blen + 1);
  }
else
  {
    diff = memcmp (a->text, b->text, MIN (alen, blen));
    if (!diff)
      diff = _GL_CMP (alen, blen);
  }

The xmemcoll0 function internally uses strcoll() which respects the locale's collation rules. In en_US.UTF-8 locale, lowercase and uppercase letters are interleaved (a, A, b, B, ...).

However, in uutils sort, the default comparison always uses byte-wise comparison.

pub fn custom_str_cmp(
    a: &[u8],
    b: &[u8],
    ignore_non_printing: bool,
    ignore_non_dictionary: bool,
    ignore_case: bool,
) -> Ordering {
    if !(ignore_case || ignore_non_dictionary || ignore_non_printing) {
        // There are no custom settings. Fall back to the default strcmp, which is faster.
        return a.cmp(b);  // Byte comparison, ignores locale
    }
    ...
}

The a.cmp(b) performs a simple byte comparison (equivalent to memcmp), which always follows ASCII order regardless of the locale setting.

Test / Reproduction Steps

# GNU sort (en_US.UTF-8 locale)
$ printf 'a\nA\nb\nB\n' | LC_ALL=en_US.UTF-8 sort
a
A
b
B

# uutils sort (en_US.UTF-8 locale)
$ printf 'a\nA\nb\nB\n' | LC_ALL=en_US.UTF-8 coreutils sort
A
B
a
b

# Both should be identical in C locale
$ printf 'a\nA\nb\nB\n' | LC_ALL=C sort
A
B
a
b

$ printf 'a\nA\nb\nB\n' | LC_ALL=C coreutils sort
A
B
a
b

Impact

Sorting output differs from GNU sort when using non-C locales (e.g., en_US.UTF-8).

Recommendations

Implement locale-based collation using strcoll() via FFI or a Unicode collation library.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions