diff --git a/dictionary/cmudict-0.7b b/dictionary/cmudict-0.7b index e466c291a6..2e3fec2cdf 100644 --- a/dictionary/cmudict-0.7b +++ b/dictionary/cmudict-0.7b @@ -35471,7 +35471,7 @@ DZIUBA JH IY0 UW1 B AH0 DZIUK JH IY0 UW1 K DZOKHAR JH OW2 K AA1 R D_C D IY1 S IY1 -DÉJÀ D EY2 JH AA1 +DEJA D EY2 JH AA1 E IY1 E'S IY1 Z E-MAIL IY1 M EY2 L diff --git a/src/arpabet.rs b/src/arpabet.rs new file mode 100644 index 0000000000..f208713aac --- /dev/null +++ b/src/arpabet.rs @@ -0,0 +1,68 @@ +// Copyright (c) 2016 Brandon Thomas + +use error::Error; +use std::collections::HashMap; +use regex::Regex; +use std::fs::File; +use std::io::BufReader; +use std::io::BufRead; +use std::io::Read; + +pub type Word = String; +pub type Phoneme = String; +pub type Polyphone = Vec; + +pub struct ArpabetDictionary { + /// A map of lowercase words to polyphone breakdown (phones are uppercase). + /// eg. 'jungle' -> [JH, AH1, NG, G, AH0, L] + dictionary: HashMap +} + +impl ArpabetDictionary { + /// Read CMU's Arpabet Dictionary. + /// See http://www.speech.cs.cmu.edu/cgi-bin/cmudict + pub fn load_from_file(filename: &str) -> Result { + let mut f = try!(File::open(filename)); + let mut reader = BufReader::new(f); + + let mut map = HashMap::new(); + let mut buffer = String::new(); + + // Format resembles the following, + // ABBREVIATE AH0 B R IY1 V IY0 EY2 T + let re = Regex::new(r"^(\w+)\s+(.*)\n$").unwrap(); + + while try!(reader.read_line(&mut buffer)) > 0 { + match re.captures(&buffer) { + None => {}, + Some(caps) => { + let word_match = caps.at(1); + let phonemes_match = caps.at(2); + + if word_match.is_some() && phonemes_match.is_some() { + let word = word_match.unwrap().to_lowercase(); + let split = phonemes_match.unwrap().split(" "); + let v1 = split.collect::>(); + let v2 = v1.iter().map(|s| s.to_string()).collect::>(); + map.insert(word, v2); + } + }, + } + buffer.clear(); + } + + if map.is_empty() { + Err(Error::EmptyFile) + } else { + Ok(ArpabetDictionary { dictionary: map }) + } + } + + /// Get a polyphone from the dictionary. + pub fn get(&self, word: &str) -> Option { + self.dictionary.get(word).and_then(|p| { + Some(p.iter().map(|s| s.to_string()).collect::>()) + }) + } +} + diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000000..dd467a1557 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,22 @@ +// Copyright (c) 2016 Brandon Thomas + +use std::error; +use std::io; +use std::fmt; +use std::convert::From; + +#[derive(Debug)] +pub enum Error { + /// The file was empty or did not have parsable contents. + EmptyFile, + + /// Wraps an IoError. + IoError { cause: io::Error }, +} + +impl From for Error { + fn from(error: io::Error) -> Error { + Error::IoError { cause: error } + } +} + diff --git a/src/main.rs b/src/main.rs index 34d3797381..ac15800bf2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ extern crate hound; extern crate iron; #[macro_use] extern crate log; +extern crate regex; extern crate resolve; extern crate router; extern crate rustc_serialize; @@ -13,26 +14,28 @@ extern crate time; extern crate toml; extern crate urlencoded; +pub mod arpabet; +pub mod atom; +pub mod error; pub mod config; pub mod dictionary; pub mod handlers; pub mod logger; pub mod words; -use std::path::{Path, PathBuf}; - +use arpabet::ArpabetDictionary; use clap::{App, Arg, ArgMatches}; -use iron::prelude::*; -use router::Router; -use resolve::hostname; use config::Config; - +use dictionary::VocabularyLibrary; use handlers::audio_synth_handler::AudioSynthHandler; use handlers::error_filter::ErrorFilter; use handlers::file_server_handler::FileServerHandler; use handlers::vocab_list_handler::VocabListHandler; +use iron::prelude::*; use logger::SimpleLogger; -use dictionary::VocabularyLibrary; +use resolve::hostname; +use router::Router; +use std::path::{Path, PathBuf}; fn main() { SimpleLogger::init().unwrap(); @@ -56,6 +59,8 @@ fn main() { get_hostname(); + read_arpabet(); + start_server(&config, port); } @@ -105,3 +110,13 @@ fn get_hostname() { let err = unsafe {gethostname (vec::raw::to_mut_ptr(buf) as *mut i8, len as u64)}; if err != 0 { println("oops, gethostname failed"); return; }*/ } + +fn read_arpabet() { + // TODO: Configurable path. + let dict = ArpabetDictionary::load_from_file("./dictionary/cmudict-0.7b").unwrap(); + + let result = dict.get("nintendo"); + + println!("Result: {:?}", result); +} +