fix: numeric sort (-n) does not recognize thousand separators (#10339)

This commit is contained in:
Kaua Klassmann
2026-01-21 21:48:50 +01:00
committed by GitHub
parent 786a33dd2c
commit 1a64417aae
16 changed files with 167 additions and 35 deletions
+12 -1
View File
@@ -47,7 +47,6 @@ use uucore::display::Quotable;
use uucore::error::{FromIo, strip_errno};
use uucore::error::{UError, UResult, USimpleError, UUsageError};
use uucore::extendedbigdecimal::ExtendedBigDecimal;
use uucore::format_usage;
#[cfg(feature = "i18n-collator")]
use uucore::i18n::collator::locale_cmp;
use uucore::i18n::decimal::locale_decimal_separator;
@@ -59,6 +58,7 @@ use uucore::posix::{MODERN, TRADITIONAL};
use uucore::show_error;
use uucore::translate;
use uucore::version_cmp::version_cmp;
use uucore::{format_usage, i18n};
use crate::buffer_hint::automatic_buffer_size;
use crate::tmp_dir::TmpDirWrapper;
@@ -1086,11 +1086,22 @@ impl FieldSelector {
};
let mut range_str = &line[self.get_range(line, tokens)];
if self.settings.mode == SortMode::Numeric || self.settings.mode == SortMode::HumanNumeric {
// Get the thousands separator from the locale, handling cases where the separator is empty or multi-character
let locale_thousands_separator = i18n::decimal::locale_grouping_separator().as_bytes();
// Upstream GNU coreutils ignore multibyte thousands separators
// (FIXME in C source). We keep the same single-byte behavior.
let thousands_separator = match locale_thousands_separator {
[b] => Some(*b),
_ => None,
};
// Parse NumInfo for this number.
let (info, num_range) = NumInfo::parse(
range_str,
&NumInfoParseSettings {
accept_si_units: self.settings.mode == SortMode::HumanNumeric,
thousands_separator,
..Default::default()
},
);
+34 -2
View File
@@ -37,15 +37,47 @@ pub fn locale_decimal_separator() -> &'static str {
DECIMAL_SEP.get_or_init(|| get_decimal_separator(get_numeric_locale().0.clone()))
}
/// Return the grouping separator for the given locale
fn get_grouping_separator(loc: Locale) -> String {
let data_locale = DataLocale::from(loc);
let request = DataRequest {
id: DataIdentifierBorrowed::for_locale(&data_locale),
metadata: DataRequestMetadata::default(),
};
let response: DataResponse<DecimalSymbolsV1> =
icu_decimal::provider::Baked.load(request).unwrap();
response.payload.get().grouping_separator().to_string()
}
/// Return the grouping separator from the language we're working with.
/// Example:
/// Say we need to format 1,000
/// en_US: 1,000 -> grouping separator is ','
/// fr_FR: 1 000 -> grouping separator is '\u{202f}'
pub fn locale_grouping_separator() -> &'static str {
static GROUPING_SEP: OnceLock<String> = OnceLock::new();
GROUPING_SEP.get_or_init(|| get_grouping_separator(get_numeric_locale().0.clone()))
}
#[cfg(test)]
mod tests {
use icu_locale::locale;
use super::get_decimal_separator;
use super::{get_decimal_separator, get_grouping_separator};
#[test]
fn test_simple_separator() {
fn test_simple_decimal_separator() {
assert_eq!(get_decimal_separator(locale!("en")), ".");
assert_eq!(get_decimal_separator(locale!("fr")), ",");
}
#[test]
fn test_simple_grouping_separator() {
assert_eq!(get_grouping_separator(locale!("en")), ",");
assert_eq!(get_grouping_separator(locale!("fr")), "\u{202f}");
}
}
+12 -4
View File
@@ -258,6 +258,14 @@ fn test_multiple_decimals_numeric() {
);
}
#[test]
fn test_multiple_groupings_numeric() {
test_helper(
"multiple_groupings_numeric",
&["-n", "--numeric-sort", "--sort=numeric", "--sort=n"],
);
}
#[test]
fn test_numeric_with_trailing_invalid_chars() {
test_helper(
@@ -2359,18 +2367,18 @@ _
__
1
_
2,5
_
2.4
___
2,5
_
2.,,3
__
2.4
___
2,,3
_
2.4
___
2,,3
_
1a
_
2b
@@ -21,10 +21,10 @@ CARAvan
8.013
45
46.89
576,446.88800000
576,446.890
4567.
37800
576,446.88800000
576,446.890
4798908.340000000000
4798908.45
4798908.8909800
@@ -67,18 +67,18 @@ __
46.89
_____
_____
576,446.88800000
___
________________
576,446.890
___
___________
4567.
_____
____________________
>>>>37800
_____
_________
576,446.88800000
___
________________
576,446.890
___
___________
4798908.340000000000
____________________
____________________
@@ -24,10 +24,10 @@ CARAvan
8.013
45
46.89
576,446.890
576,446.88800000
4567.
37800
576,446.88800000
576,446.890
4798908.340000000000
4798908.45
4798908.8909800
@@ -50,14 +50,14 @@ _____
__
46.89
_____
576,446.890
___
576,446.88800000
___
4567.
_____
>>>>37800
_____
576,446.88800000
___
576,446.890
___
4798908.340000000000
____________________
4798908.45
@@ -11,9 +11,10 @@
8.013
45
46.89
576,446.890
4567.
37800
576,446.88800000
576,446.890
4798908.340000000000
4798908.45
4798908.8909800
@@ -24,12 +24,14 @@ _____
__
46.89
_____
576,446.890
___
4567.
_____
>>>>37800
_____
576,446.88800000
___
576,446.890
___
4798908.340000000000
____________________
4798908.45
@@ -1,9 +1,10 @@
4798908.8909800
4798908.45
4798908.340000000000
576,446.890
576,446.88800000
37800
4567.
576,446.890
46.89
45
8.013
@@ -4,12 +4,14 @@ _______________
__________
4798908.340000000000
____________________
576,446.890
___
576,446.88800000
___
>>>>37800
_____
4567.
_____
576,446.890
___
46.89
_____
45
+2 -2
View File
@@ -21,8 +21,6 @@ CARAvan
8.013
45
46.89
576,446.88800000
576,446.890
4567..457
4567.
4567.1
@@ -30,6 +28,8 @@ CARAvan
37800
45670.89079.098
45670.89079.1
576,446.88800000
576,446.890
4798908.340000000000
4798908.45
4798908.8909800
@@ -67,12 +67,6 @@ __
46.89
_____
_____
576,446.88800000
___
________________
576,446.890
___
___________
>>>>>>>>>>4567..457
_____
___________________
@@ -94,6 +88,12 @@ _____________________
>>>>>>45670.89079.1
___________
___________________
576,446.88800000
___
________________
576,446.890
___
___________
4798908.340000000000
____________________
____________________
+15
View File
@@ -0,0 +1,15 @@
CARAvan
1.234
2.000
2.000,50
22
23,.
111
210
1,234
12,34
1,999.99
2,000
@@ -0,0 +1,45 @@
^ no match for key
^ no match for key
^ no match for key
^ no match for key
^ no match for key
^ no match for key
CARAvan
^ no match for key
_______
>1.234
_____
______
2.000
_____
_____
2.000,50
_____
________
22
__
__
23,.
__
____
111
___
___
>210
___
____
1,234
_
_____
12,34
__
_____
>>1,999.99
_
__________
>>>2,000
_
________
+15
View File
@@ -0,0 +1,15 @@
1,234
12,34
1.234
2.000
2,000
111
CARAvan
22
23,.
210
1,999.99
2.000,50