Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/uu/tr/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ tr-error-missing-operand = missing operand
tr-error-missing-operand-translating = missing operand after { $set }
Two strings must be given when translating.
tr-error-missing-operand-deleting-squeezing = missing operand after { $set }
Two strings must be given when deleting and squeezing.
Two strings must be given when both deleting and squeezing repeats.
tr-error-extra-operand-deleting-without-squeezing = extra operand { $operand }
Only one string may be given when deleting without squeezing repeats.
tr-error-extra-operand-simple = extra operand { $operand }
Expand All @@ -34,7 +34,7 @@ tr-error-char-repeat-in-set1 = the [c*] repeat construct may not appear in strin
tr-error-invalid-repeat-count = invalid repeat count { $count } in [c*n] construct
tr-error-empty-set2-when-not-truncating = when not truncating set1, string2 must be non-empty
tr-error-class-except-lower-upper-in-set2 = when translating, the only character classes that may appear in set2 are 'upper' and 'lower'
tr-error-class-in-set2-not-matched = when translating, every 'upper'/'lower' in set2 must be matched by a 'upper'/'lower' in the same position in set1
tr-error-class-in-set2-not-matched = misaligned [:upper:] and/or [:lower:] construct
tr-error-set1-longer-set2-ends-in-class = when translating with string1 longer than string2,
the latter string must not end with a character class
tr-error-complement-more-than-one-unique = when translating with complemented character classes,
Expand Down
4 changes: 2 additions & 2 deletions src/uu/tr/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ tr-error-missing-operand = opérande manquant
tr-error-missing-operand-translating = opérande manquant après { $set }
Deux chaînes doivent être données lors de la traduction.
tr-error-missing-operand-deleting-squeezing = opérande manquant après { $set }
Deux chaînes doivent être données lors de la suppression et compression.
Deux chaînes doivent être données lors de la suppression et de la compression des répétitions.
tr-error-extra-operand-deleting-without-squeezing = opérande supplémentaire { $operand }
Une seule chaîne peut être donnée lors de la suppression sans compression des répétitions.
tr-error-extra-operand-simple = opérande supplémentaire { $operand }
Expand All @@ -35,7 +35,7 @@ tr-error-char-repeat-in-set1 = la construction de répétition [c*] ne peut pas
tr-error-invalid-repeat-count = nombre de répétitions invalide { $count } dans la construction [c*n]
tr-error-empty-set2-when-not-truncating = quand on ne tronque pas set1, string2 doit être non-vide
tr-error-class-except-lower-upper-in-set2 = lors de la traduction, les seules classes de caractères qui peuvent apparaître dans set2 sont 'upper' et 'lower'
tr-error-class-in-set2-not-matched = lors de la traduction, chaque 'upper'/'lower' dans set2 doit être associé à un 'upper'/'lower' à la même position dans set1
tr-error-class-in-set2-not-matched = les structures [:upper:] ou [:lower:] ne sont pas alignées correctement
tr-error-set1-longer-set2-ends-in-class = lors de la traduction avec string1 plus long que string2,
cette dernière chaîne ne doit pas se terminer par une classe de caractères
tr-error-complement-more-than-one-unique = lors de la traduction avec des classes de caractères complémentées,
Expand Down
20 changes: 13 additions & 7 deletions src/uu/tr/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,10 @@ impl Sequence {
})
.collect();

// For every upper/lower in set2, there must be an upper/lower in set1 at the same position. The position is calculated by expanding everything before the upper/lower in both sets
// For every upper/lower in set2, there must be an upper/lower in set1 at the same position. The position is calculated by expanding everything before the upper/lower in both sets.
// Only when translating: with -d, set2 is the squeeze set and lines up with nothing.
for (set2_pos, set2_item) in set2.iter().enumerate() {
if matches!(set2_item, Self::Class(_)) {
if translating && matches!(set2_item, Self::Class(_)) {
let mut set2_part_solved_len = 0;
if set2_pos >= 1 {
set2_part_solved_len =
Expand All @@ -329,7 +330,10 @@ impl Sequence {

let mut class_matches = false;
for (set1_pos, set1_item) in set1.iter().enumerate() {
if matches!(set1_item, Self::Class(_)) {
// Only an 'upper'/'lower' in set1 can line up with one in
// set2: any other class there leaves the mapping
// undefined, so GNU rejects it.
if matches!(set1_item, Self::Class(Class::Upper | Class::Lower)) {
let mut set1_part_solved_len = 0;
if set1_pos >= 1 {
set1_part_solved_len =
Expand Down Expand Up @@ -401,10 +405,12 @@ impl Sequence {
} else {
set1_solved.truncate(set2_solved.len());
}
} else if matches!(
set2.last().copied(),
Some(Self::Class(Class::Upper | Class::Lower))
) {
} else if translating
&& matches!(
set2.last().copied(),
Some(Self::Class(Class::Upper | Class::Lower))
)
{
return Err(SequenceError::whole_set(
BadSequence::Set1LongerSet2EndsInClass,
1,
Expand Down
44 changes: 43 additions & 1 deletion tests/by-util/test_tr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,55 @@ fn test_translate_and_squeeze_multiple_lines() {
.stdout_is("yaay\nyaay"); // spell-checker:disable-line
}

/// An 'upper'/'lower' in SET2 must line up with an 'upper'/'lower' in SET1;
/// any other class there leaves the mapping undefined. GNU calls that a
/// misaligned construct.
#[test]
fn test_misaligned_upper_lower_construct() {
for sets in [
["[:alpha:]", "[:upper:]"],
["[:digit:]", "[:upper:]"],
["abc", "[:upper:]"],
["a[:lower:]", "[:upper:]b"],
["[:lower:]", "[:upper:][:lower:]"],
] {
new_ucmd!()
.args(&sets)
.pipe_in("aZ1")
.fails_with_code(1)
.no_stdout()
.stderr_contains("tr: misaligned [:upper:] and/or [:lower:] construct\n");
}
}

/// The alignment rule is about translating only: with -d, SET2 is the squeeze
/// set and lines up with nothing.
#[test]
fn test_misaligned_construct_not_checked_when_deleting() {
new_ucmd!()
.args(&["-ds", "[:alpha:]", "[:upper:]"])
.pipe_in("aZ1")
.succeeds()
.stdout_is("1");
}

/// SET1 longer than SET2 keeps its own message, which GNU also has.
#[test]
fn test_set1_longer_than_set2_ending_in_class() {
new_ucmd!()
.args(&["[:upper:][:lower:]", "[:lower:]"])
.pipe_in("aZ1")
.fails_with_code(1)
.stderr_contains("when translating with string1 longer than string2,\n");
}

#[test]
fn test_delete_and_squeeze_one_set() {
new_ucmd!()
.args(&["-ds", "a-z"])
.fails()
.stderr_contains("missing operand after 'a-z'")
.stderr_contains("Two strings must be given when deleting and squeezing.");
.stderr_contains("Two strings must be given when both deleting and squeezing repeats.");
}

#[test]
Expand Down
Loading