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:
parent
0f3bc23739
commit
5674d09327
1 changed files with 42 additions and 47 deletions
|
@ -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());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue