mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge pull request #2158 from jhscheer/issue2147
tr: implement complement separately from delete or squeeze (#2147)
This commit is contained in:
commit
79068d231f
2 changed files with 74 additions and 13 deletions
|
@ -123,10 +123,17 @@ impl SymbolTranslator for DeleteAndSqueezeOperation {
|
||||||
|
|
||||||
struct TranslateOperation {
|
struct TranslateOperation {
|
||||||
translate_map: FnvHashMap<usize, char>,
|
translate_map: FnvHashMap<usize, char>,
|
||||||
|
complement: bool,
|
||||||
|
s2_last: char,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TranslateOperation {
|
impl TranslateOperation {
|
||||||
fn new(set1: ExpandSet, set2: &mut ExpandSet, truncate: bool) -> TranslateOperation {
|
fn new(
|
||||||
|
set1: ExpandSet,
|
||||||
|
set2: &mut ExpandSet,
|
||||||
|
truncate: bool,
|
||||||
|
complement: bool,
|
||||||
|
) -> TranslateOperation {
|
||||||
let mut map = FnvHashMap::default();
|
let mut map = FnvHashMap::default();
|
||||||
let mut s2_prev = '_';
|
let mut s2_prev = '_';
|
||||||
for i in set1 {
|
for i in set1 {
|
||||||
|
@ -139,14 +146,26 @@ impl TranslateOperation {
|
||||||
map.insert(i as usize, s2_prev);
|
map.insert(i as usize, s2_prev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TranslateOperation { translate_map: map }
|
TranslateOperation {
|
||||||
|
translate_map: map,
|
||||||
|
complement,
|
||||||
|
s2_last: set2.last().unwrap_or(s2_prev),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolTranslator for TranslateOperation {
|
impl SymbolTranslator for TranslateOperation {
|
||||||
fn translate(&self, c: char, _prev_c: char) -> Option<char> {
|
fn translate(&self, c: char, _prev_c: char) -> Option<char> {
|
||||||
|
if self.complement {
|
||||||
|
Some(if self.translate_map.contains_key(&(c as usize)) {
|
||||||
|
c
|
||||||
|
} else {
|
||||||
|
self.s2_last
|
||||||
|
})
|
||||||
|
} else {
|
||||||
Some(*self.translate_map.get(&(c as usize)).unwrap_or(&c))
|
Some(*self.translate_map.get(&(c as usize)).unwrap_or(&c))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TranslateAndSqueezeOperation {
|
struct TranslateAndSqueezeOperation {
|
||||||
|
@ -163,7 +182,7 @@ impl TranslateAndSqueezeOperation {
|
||||||
complement: bool,
|
complement: bool,
|
||||||
) -> TranslateAndSqueezeOperation {
|
) -> TranslateAndSqueezeOperation {
|
||||||
TranslateAndSqueezeOperation {
|
TranslateAndSqueezeOperation {
|
||||||
translate: TranslateOperation::new(set1, set2, truncate),
|
translate: TranslateOperation::new(set1, set2, truncate, complement),
|
||||||
squeeze: SqueezeOperation::new(set2_, complement),
|
squeeze: SqueezeOperation::new(set2_, complement),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,8 +217,8 @@ fn translate_input<T: SymbolTranslator>(
|
||||||
// Set `prev_c` to the post-translate character. This
|
// Set `prev_c` to the post-translate character. This
|
||||||
// allows the squeeze operation to correctly function
|
// allows the squeeze operation to correctly function
|
||||||
// after the translate operation.
|
// after the translate operation.
|
||||||
if res.is_some() {
|
if let Some(rc) = res {
|
||||||
prev_c = res.unwrap();
|
prev_c = rc;
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
});
|
});
|
||||||
|
@ -300,11 +319,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if complement_flag && !delete_flag && !squeeze_flag {
|
|
||||||
show_error!("-c is only supported with -d or -s");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let stdin = stdin();
|
let stdin = stdin();
|
||||||
let mut locked_stdin = stdin.lock();
|
let mut locked_stdin = stdin.lock();
|
||||||
let stdout = stdout();
|
let stdout = stdout();
|
||||||
|
@ -339,8 +353,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut set2 = ExpandSet::new(sets[1].as_ref());
|
let mut set2 = ExpandSet::new(sets[1].as_ref());
|
||||||
let op = TranslateOperation::new(set1, &mut set2, truncate_flag);
|
let op = TranslateOperation::new(set1, &mut set2, truncate_flag, complement_flag);
|
||||||
translate_input(&mut locked_stdin, &mut buffered_stdout, op)
|
translate_input(&mut locked_stdin, &mut buffered_stdout, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
0
|
0
|
||||||
|
|
|
@ -59,6 +59,53 @@ fn test_delete_complement_2() {
|
||||||
.stdout_is("01234567890");
|
.stdout_is("01234567890");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_complement1() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["-c", "a", "X"])
|
||||||
|
.pipe_in("ab")
|
||||||
|
.run()
|
||||||
|
.stdout_is("aX");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_complement2() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["-c", "0-9", "x"])
|
||||||
|
.pipe_in("Phone: 01234 567890")
|
||||||
|
.run()
|
||||||
|
.stdout_is("xxxxxxx01234x567890");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_complement3() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["-c", "abcdefgh", "123"])
|
||||||
|
.pipe_in("the cat and the bat")
|
||||||
|
.run()
|
||||||
|
.stdout_is("3he3ca33a3d33he3ba3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_complement4() {
|
||||||
|
// $ echo -n '0x1y2z3' | tr -c '0-@' '*-~'
|
||||||
|
// 0~1~2~3
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["-c", "0-@", "*-~"])
|
||||||
|
.pipe_in("0x1y2z3")
|
||||||
|
.run()
|
||||||
|
.stdout_is("0~1~2~3");
|
||||||
|
|
||||||
|
// TODO: fix this
|
||||||
|
// $ echo '0x1y2z3' | tr -c '\0-@' '*-~'
|
||||||
|
// 0a1b2c3
|
||||||
|
// new_ucmd!()
|
||||||
|
// .args(&["-c", "\\0-@", "*-~"])
|
||||||
|
// .pipe_in("0x1y2z3")
|
||||||
|
// .run()
|
||||||
|
// .stdout_is("0a1b2c3");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_squeeze() {
|
fn test_squeeze() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue