diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 8c27910dce8..01ddc63fbe0 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -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() }, ); diff --git a/src/uucore/src/lib/features/i18n/decimal.rs b/src/uucore/src/lib/features/i18n/decimal.rs index 9fa2d8d7bc7..0a901143c6b 100644 --- a/src/uucore/src/lib/features/i18n/decimal.rs +++ b/src/uucore/src/lib/features/i18n/decimal.rs @@ -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 = + 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 = 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}"); + } } diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 0106d719fad..e794898a286 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -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 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected index 59541af3252..a781a36bba8 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected @@ -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 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected.debug b/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected.debug index b7b76e58986..a00067b1ee6 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected.debug +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric.expected.debug @@ -67,18 +67,18 @@ __ 46.89 _____ _____ -576,446.88800000 -___ -________________ -576,446.890 -___ -___________ 4567. _____ ____________________ >>>>37800 _____ _________ +576,446.88800000 +___ +________________ +576,446.890 +___ +___________ 4798908.340000000000 ____________________ ____________________ diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected index 0ccdd84c059..36eeda637f7 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected @@ -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 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected.debug b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected.debug index 66a98b20879..3fba8903042 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected.debug +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_stable.expected.debug @@ -50,14 +50,14 @@ _____ __ 46.89 _____ -576,446.890 -___ -576,446.88800000 -___ 4567. _____ >>>>37800 _____ +576,446.88800000 +___ +576,446.890 +___ 4798908.340000000000 ____________________ 4798908.45 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected index cd4256c5f46..cb27c6664ce 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected @@ -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 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected.debug b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected.debug index 663a4b3a918..dd6e8dfcc67 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected.debug +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique.expected.debug @@ -24,12 +24,14 @@ _____ __ 46.89 _____ -576,446.890 -___ 4567. _____ >>>>37800 _____ +576,446.88800000 +___ +576,446.890 +___ 4798908.340000000000 ____________________ 4798908.45 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected index 97e261f1452..bbce169347f 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected @@ -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 diff --git a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected.debug b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected.debug index 01f7abf5bf2..4b01a840618 100644 --- a/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected.debug +++ b/tests/fixtures/sort/mixed_floats_ints_chars_numeric_unique_reverse.expected.debug @@ -4,12 +4,14 @@ _______________ __________ 4798908.340000000000 ____________________ +576,446.890 +___ +576,446.88800000 +___ >>>>37800 _____ 4567. _____ -576,446.890 -___ 46.89 _____ 45 diff --git a/tests/fixtures/sort/multiple_decimals_numeric.expected b/tests/fixtures/sort/multiple_decimals_numeric.expected index 8f42e7ce5da..3ef4d22e881 100644 --- a/tests/fixtures/sort/multiple_decimals_numeric.expected +++ b/tests/fixtures/sort/multiple_decimals_numeric.expected @@ -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 diff --git a/tests/fixtures/sort/multiple_decimals_numeric.expected.debug b/tests/fixtures/sort/multiple_decimals_numeric.expected.debug index 948c4869c32..0ae6d2958a5 100644 --- a/tests/fixtures/sort/multiple_decimals_numeric.expected.debug +++ b/tests/fixtures/sort/multiple_decimals_numeric.expected.debug @@ -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 ____________________ ____________________ diff --git a/tests/fixtures/sort/multiple_groupings_numeric.expected b/tests/fixtures/sort/multiple_groupings_numeric.expected new file mode 100644 index 00000000000..a6daab83676 --- /dev/null +++ b/tests/fixtures/sort/multiple_groupings_numeric.expected @@ -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 diff --git a/tests/fixtures/sort/multiple_groupings_numeric.expected.debug b/tests/fixtures/sort/multiple_groupings_numeric.expected.debug new file mode 100644 index 00000000000..57a4ae01b9a --- /dev/null +++ b/tests/fixtures/sort/multiple_groupings_numeric.expected.debug @@ -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 + _ +________ diff --git a/tests/fixtures/sort/multiple_groupings_numeric.txt b/tests/fixtures/sort/multiple_groupings_numeric.txt new file mode 100644 index 00000000000..264403a79ee --- /dev/null +++ b/tests/fixtures/sort/multiple_groupings_numeric.txt @@ -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 \ No newline at end of file