join: consider locale collation in field comparison (#9982)

Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
This commit is contained in:
WaterWhisperer
2026-01-20 14:24:30 +01:00
committed by GitHub
co-authored by Sylvestre Ledru
parent 555271d8a9
commit 98d3dbad4e
4 changed files with 43 additions and 3 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ path = "src/join.rs"
[dependencies]
clap = { workspace = true }
uucore = { workspace = true }
uucore = { workspace = true, features = ["i18n-collator"] }
memchr = { workspace = true }
thiserror = { workspace = true }
fluent = { workspace = true }
+18 -2
View File
@@ -19,6 +19,9 @@ use thiserror::Error;
use uucore::display::Quotable;
use uucore::error::{FromIo, UError, UResult, USimpleError, set_exit_code};
use uucore::format_usage;
use uucore::i18n::collator::{
AlternateHandling, CollatorOptions, locale_cmp, should_use_locale_collation, try_init_collator,
};
use uucore::line_ending::LineEnding;
use uucore::translate;
@@ -311,14 +314,16 @@ struct Input<Sep: Separator> {
separator: Sep,
ignore_case: bool,
check_order: CheckOrder,
use_locale: bool,
}
impl<Sep: Separator> Input<Sep> {
fn new(separator: Sep, ignore_case: bool, check_order: CheckOrder) -> Self {
fn new(separator: Sep, ignore_case: bool, check_order: CheckOrder, use_locale: bool) -> Self {
Self {
separator,
ignore_case,
check_order,
use_locale,
}
}
@@ -328,6 +333,8 @@ impl<Sep: Separator> Input<Sep> {
let field1 = CaseInsensitiveSlice { v: field1 };
let field2 = CaseInsensitiveSlice { v: field2 };
field1.cmp(&field2)
} else if self.use_locale {
locale_cmp(field1, field2)
} else {
field1.cmp(field2)
}
@@ -823,6 +830,10 @@ fn parse_settings(matches: &clap::ArgMatches) -> UResult<Settings> {
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
let mut opts = CollatorOptions::default();
opts.alternate_handling = Some(AlternateHandling::Shifted);
let _ = try_init_collator(opts);
let settings = parse_settings(&matches)?;
let file1 = matches.get_one::<OsString>("file1").unwrap();
@@ -989,7 +1000,12 @@ fn exec<Sep: Separator>(
settings.print_unpaired2,
)?;
let input = Input::new(sep.clone(), settings.ignore_case, settings.check_order);
let input = Input::new(
sep.clone(),
settings.ignore_case,
settings.check_order,
should_use_locale_collation(),
);
let format = if settings.autoformat {
let mut format = vec![Spec::Key];
@@ -30,6 +30,11 @@ pub fn init_collator(opts: CollatorOptions) {
.expect("Collator already initialized");
}
/// Check if locale collation should be used.
pub fn should_use_locale_collation() -> bool {
get_collating_locale().0 != DEFAULT_LOCALE
}
/// Initialize the collator for locale-aware string comparison if needed.
///
/// This function checks if the current locale requires locale-aware collation
+19
View File
@@ -580,3 +580,22 @@ fn join_emoji_delim_inner_key() {
.succeeds()
.stdout_only("b🗿a🗿u\n");
}
#[cfg(unix)]
#[test]
fn test_locale_collation() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
at.write("f1.sorted", "abc:d 2\nab:d 1\n");
at.write("f2.sorted", "abc:d y\nab:d x\n");
ts.ucmd()
.env("LC_ALL", "en_US.UTF-8")
.arg("--check-order")
.arg("f1.sorted")
.arg("f2.sorted")
.succeeds()
.stdout_contains("abc:d 2 y")
.stdout_contains("ab:d 1 x");
}