1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

tr: generaze translation

This commit is contained in:
Yury Krivopalov 2017-08-24 14:26:08 +03:00
parent c59e375c7a
commit b4d8265a07

View file

@ -32,63 +32,80 @@ static NAME: &'static str = "tr";
static VERSION: &'static str = env!("CARGO_PKG_VERSION"); static VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BUFFER_LEN: usize = 1024; const BUFFER_LEN: usize = 1024;
fn delete(set: ExpandSet, complement: bool) { trait SymbolTranslator {
let mut bset = BitSet::new(); fn translate(&self, c: &char, prev_c: &char) -> Option<char>;
let stdin = stdin(); }
let mut locked_stdin = stdin.lock();
let mut buffered_stdout = BufWriter::new(stdout());
let mut buf = String::with_capacity(BUFFER_LEN + 4);
let mut char_output_buffer: [u8; 4] = [0;4];
for c in set { struct DeleteOperation {
bset.insert(c as usize); bset: BitSet,
} complement: bool,
}
let is_allowed = |c : char| { impl DeleteOperation {
if complement { fn new(set: ExpandSet, complement: bool) -> DeleteOperation {
bset.contains(c as usize) DeleteOperation {
} else { bset: set.map(|c| c as usize).collect(),
!bset.contains(c as usize) complement: complement
} }
};
while let Ok(length) = locked_stdin.read_line(&mut buf) {
if length == 0 { break }
{ // isolation to make borrow checker happy
let filtered = buf.chars().filter(|c| is_allowed(*c));
for c in filtered {
let char_as_bytes = c.encode_utf8(&mut char_output_buffer);
buffered_stdout.write_all(char_as_bytes.as_bytes()).unwrap();
}
}
buf.clear();
} }
} }
fn tr<'a>(set1: ExpandSet<'a>, mut set2: ExpandSet<'a>) { impl SymbolTranslator for DeleteOperation {
let mut map = FnvHashMap::default(); fn translate(&self, c: &char, _prev_c: &char) -> Option<char> {
let stdin = stdin(); let uc = *c as usize;
let mut locked_stdin = stdin.lock(); if self.complement == self.bset.contains(uc) {
let mut buffered_stdout = BufWriter::new(stdout()); Some(*c)
let mut buf = String::with_capacity(BUFFER_LEN + 4); } else {
let mut output_buf = String::with_capacity(BUFFER_LEN + 4); None
}
}
}
struct TranslateOperation {
translate_map: FnvHashMap<usize, char>,
}
impl TranslateOperation {
fn new(set1: ExpandSet, set2: &mut ExpandSet) -> TranslateOperation {
let mut map = FnvHashMap::default();
let mut s2_prev = '_'; let mut s2_prev = '_';
for i in set1 { for i in set1 {
s2_prev = set2.next().unwrap_or(s2_prev); s2_prev = set2.next().unwrap_or(s2_prev);
map.insert(i as usize, s2_prev); map.insert(i as usize, s2_prev);
} }
TranslateOperation {
while let Ok(length) = locked_stdin.read_line(&mut buf) { translate_map: map,
if length == 0 { break }
{ // isolation to make borrow checker happy
let output_stream = buf.chars().map(|c| *map.get(&(c as usize)).unwrap_or(&c));
output_buf.extend(output_stream);
buffered_stdout.write_all(output_buf.as_bytes()).unwrap();
} }
}
}
impl SymbolTranslator for TranslateOperation {
fn translate(&self, c: &char, _prev_c: &char) -> Option<char> {
Some(*self.translate_map.get(&(*c as usize)).unwrap_or(c))
}
}
fn translate_input<T: SymbolTranslator>(input: &mut BufRead, output: &mut Write, translator: T) {
let mut buf = String::with_capacity(BUFFER_LEN + 4);
let mut output_buf = String::with_capacity(BUFFER_LEN + 4);
// let mut char_output_buffer: [u8; 4] = [0;4];
while let Ok(length) = input.read_line(&mut buf) {
let mut prev_c = 0 as char;
if length == 0 { break }
{ // isolation to make borrow checker happy
let filtered = buf.chars().filter_map(|c| {
let res = translator.translate(&c, &prev_c);
if res.is_some() {
prev_c = c;
}
res
});
output_buf.extend(filtered);
output.write_all(output_buf.as_bytes()).unwrap();
}
buf.clear(); buf.clear();
output_buf.clear(); output_buf.clear();
} }
@ -110,6 +127,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
opts.optflag("C", "", "same as -c"); opts.optflag("C", "", "same as -c");
opts.optflag("d", "delete", "delete characters in SET1"); opts.optflag("d", "delete", "delete characters in SET1");
opts.optflag("h", "help", "display this help and exit"); opts.optflag("h", "help", "display this help and exit");
opts.optflag("s", "squeeze", "");
opts.optflag("V", "version", "output version information and exit"); opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) { let matches = match opts.parse(&args[1..]) {
@ -144,13 +162,21 @@ pub fn uumain(args: Vec<String>) -> i32 {
return 1; return 1;
} }
let stdin = stdin();
let mut locked_stdin = stdin.lock();
let stdout = stdout();
let locked_stdout = stdout.lock();
let mut buffered_stdout = BufWriter::new(locked_stdout);
if dflag { if dflag {
let set1 = ExpandSet::new(sets[0].as_ref()); let set1 = ExpandSet::new(sets[0].as_ref());
delete(set1, cflag); let delete_op = DeleteOperation::new(set1, cflag);
translate_input(&mut locked_stdin, &mut buffered_stdout, delete_op);
} else { } else {
let set1 = ExpandSet::new(sets[0].as_ref()); let set1 = ExpandSet::new(sets[0].as_ref());
let set2 = ExpandSet::new(sets[1].as_ref()); let mut set2 = ExpandSet::new(sets[1].as_ref());
tr(set1, set2); let op = TranslateOperation::new(set1, &mut set2);
translate_input(&mut locked_stdin, &mut buffered_stdout, op)
} }
0 0