1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

fixup! tr: implement translate and squeeze (-s) mode

This commit is contained in:
Jeffrey Finkelstein 2021-05-01 13:01:55 -04:00
parent 0f3bc23739
commit 5674d09327

View file

@ -151,6 +151,35 @@ impl SymbolTranslator for TranslateOperation {
} }
} }
struct TranslateAndSqueezeOperation {
translate: TranslateOperation,
squeeze: SqueezeOperation,
}
impl TranslateAndSqueezeOperation {
fn new(
set1: ExpandSet,
set2: &mut ExpandSet,
set2_: ExpandSet,
truncate: bool,
complement: bool,
) -> TranslateAndSqueezeOperation {
TranslateAndSqueezeOperation {
translate: TranslateOperation::new(set1, set2, truncate),
squeeze: SqueezeOperation::new(set2_, complement),
}
}
}
impl SymbolTranslator for TranslateAndSqueezeOperation {
fn translate(&self, c: char, prev_c: char) -> Option<char> {
// `unwrap()` will never panic because `Translate.translate()`
// always returns `Some`.
self.squeeze
.translate(self.translate.translate(c, 0 as char).unwrap(), prev_c)
}
}
fn translate_input<T: SymbolTranslator>( fn translate_input<T: SymbolTranslator>(
input: &mut dyn BufRead, input: &mut dyn BufRead,
output: &mut dyn Write, output: &mut dyn Write,
@ -168,8 +197,11 @@ fn translate_input<T: SymbolTranslator>(
// isolation to make borrow checker happy // isolation to make borrow checker happy
let filtered = buf.chars().filter_map(|c| { let filtered = buf.chars().filter_map(|c| {
let res = translator.translate(c, prev_c); let res = translator.translate(c, prev_c);
// Set `prev_c` to the post-translate character. This
// allows the squeeze operation to correctly function
// after the translate operation.
if res.is_some() { if res.is_some() {
prev_c = c; prev_c = res.unwrap();
} }
res res
}); });
@ -282,53 +314,16 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let op = SqueezeOperation::new(set1, complement_flag); let op = SqueezeOperation::new(set1, complement_flag);
translate_input(&mut locked_stdin, &mut buffered_stdout, op); translate_input(&mut locked_stdin, &mut buffered_stdout, op);
} else { } else {
// Define a closure that computes the translation using a hash map.
//
// The `unwrap()` should never panic because the
// `TranslateOperation.translate()` method always returns
// `Some`.
let mut set2 = ExpandSet::new(sets[1].as_ref()); let mut set2 = ExpandSet::new(sets[1].as_ref());
let translator = TranslateOperation::new(set1, &mut set2, truncate_flag); let set2_ = ExpandSet::new(sets[1].as_ref());
let translate = |c| translator.translate(c, 0 as char).unwrap(); let op = TranslateAndSqueezeOperation::new(
set1,
// Prepare some variables to be used for the closure that &mut set2,
// computes the squeeze operation. set2_,
// complement_flag,
// The `squeeze()` closure needs to be defined anew for truncate_flag,
// each line of input, but these variables do not change );
// while reading the input so they can be defined before translate_input(&mut locked_stdin, &mut buffered_stdout, op);
// the `while` loop.
let set2 = ExpandSet::new(sets[1].as_ref());
let squeezer = SqueezeOperation::new(set2, complement_flag);
// Prepare some memory to read each line of the input (`buf`) and to write
let mut buf = String::with_capacity(BUFFER_LEN + 4);
// Loop over each line of stdin.
while let Ok(length) = locked_stdin.read_line(&mut buf) {
if length == 0 {
break;
}
// Define a closure that computes the squeeze operation.
//
// We keep track of the previously seen character on
// each call to `squeeze()`, but we need to reset the
// `prev_c` variable at the beginning of each line of
// the input. That's why we define the closure inside
// the `while` loop.
let mut prev_c = 0 as char;
let squeeze = |c| {
let result = squeezer.translate(c, prev_c);
prev_c = c;
result
};
// First translate, then squeeze each character of the input line.
let filtered: String = buf.chars().map(translate).filter_map(squeeze).collect();
buf.clear();
buffered_stdout.write_all(filtered.as_bytes()).unwrap();
}
} }
} else { } else {
let mut set2 = ExpandSet::new(sets[1].as_ref()); let mut set2 = ExpandSet::new(sets[1].as_ref());