123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- use std::env;
- use std::fs::File;
- use std::io::BufRead;
- use std::io::BufReader;
- use std::io::Error;
- use std::iter::Iterator;
- use regex::Regex;
- use unidecode::unidecode;
- use std::collections::HashSet;
- #[derive(Default, Debug)]
- struct Dictionary {
- words: Vec<String>,
- iter_position: usize,
- }
- impl Dictionary {
- fn words_from_iterable(
- lines: impl Iterator<Item = Result<String, Error>>,
- ) -> Result<Vec<String>, Error> {
- // aux_set is used only to deduplicate
- // so we're still using a normal Vec, and perform deduplication at load time
- let mut aux_set = HashSet::new();
- lines
- .map(|res| match res {
- Ok(word) => Ok(line_to_word(word.as_str())),
- _ => res,
- })
- .filter(|res| match res {
- Ok(word) => aux_set.insert(word.clone()),
- _ => false,
- })
- .collect()
- }
- fn load(fname: String) -> Result<Self, Error> {
- let maybe_words = File::open(fname)
- .and_then(|open_f| Ok(BufReader::new(open_f)))
- .and_then(|buf| Self::words_from_iterable(buf.lines()));
- match maybe_words {
- Ok(words) => Ok(Dictionary {
- words,
- iter_position: 0,
- }),
- Err(err) => Err(err),
- }
- }
- }
- impl Iterator for Dictionary {
- type Item = String;
- fn next(&mut self) -> Option<Self::Item> {
- if self.words.len() >= self.iter_position {
- None
- } else {
- let v = self.words[self.iter_position].clone();
- self.iter_position += 1;
- Some(v)
- }
- }
- }
- fn line_to_word(line: &str) -> String {
- unidecode(&line.to_string()).to_lowercase().replace("'", "")
- }
- // filtri {{{
- // i filtri dovrebbero essere creati da una struct Config{} creata parsando gli argomenti
- #[allow(dead_code)]
- fn matches_regexp(regexp: &str) -> impl std::ops::FnMut(&&String) -> bool {
- // filtro
- let re = Regex::new(regexp).unwrap();
- move |w| re.is_match(w.as_str())
- }
- fn sort_word(word: &str) -> Result<String, impl std::error::Error> {
- // funzione ausiliaria, utile per la is_anagram e cose simili
- // ritorna una COPIA
- // esempio: house -> ehosu
- let mut w_bytes = word.to_string().into_bytes();
- w_bytes.sort();
- String::from_utf8(w_bytes)
- }
- fn is_anagram(word: &str) -> impl std::ops::FnMut(&&String) -> bool {
- // filtro
- let sorted_word = sort_word(line_to_word(word).as_str()).unwrap();
- move |w| {
- if sorted_word.len() != w.len() {
- // this check doesn't add any correctness to the algorithm, but
- // is a small optimization: avoids sorting w if the length is different
- false
- } else {
- let sorted_other = sort_word(w.as_str()).unwrap();
- sorted_word == sorted_other
- }
- }
- }
- // filtri }}}
- fn main() {
- let args: Vec<String> = env::args().collect();
- let fname = &args[1];
- let pattern = &args[2];
- let d = Dictionary::load(fname.to_string());
- //let filter = matches_regexp(pattern);
- let filter = is_anagram(pattern);
- if let Ok(dict) = d {
- for w in dict.words.iter().filter(filter) {
- println!("{}", w);
- }
- };
- }
|