MCPcopy Create free account
hub / github.com/daisy/MathCAT / replace_array_string

Method replace_array_string

src/speech.rs:789–863  ·  view source on GitHub ↗
(&self, rules_with_context: &'r mut SpeechRulesWithContext<'c, 's,'m>, mathml: Element<'c>)

Source from the content-addressed store, hash-verified

787 }
788
789 pub fn replace_array_string<'c, 's:'c, 'm:'c>(&self, rules_with_context: &'r mut SpeechRulesWithContext<'c, 's,'m>, mathml: Element<'c>) -> Result<String> {
790 // loop over the replacements and build up a vector of strings, excluding empty ones.
791 // * eliminate any redundance
792 // * add/replace auto-pauses
793 // * join the remaining vector together
794 let mut replacement_strings = Vec::with_capacity(self.replacements.len()); // probably conservative guess
795 for replacement in self.replacements.iter() {
796 let string: String = rules_with_context.replace(replacement, mathml)?;
797 if !string.is_empty() {
798 replacement_strings.push(string);
799 }
800 }
801
802 if replacement_strings.is_empty() {
803 return Ok( "".to_string() );
804 }
805 // delete an optional text that is repetitive
806 // we do this by looking for the optional text marker, and if present, check for repetition at end of previous string
807 // if repetitive, we delete the optional string
808 // if not, we leave the markers because the repetition might happen several "levels" up
809 // this could also be done in a final cleanup of the entire string (where we remove any markers),
810 // but the match is harder (rust regex lacks look behind pattern match) and it is less efficient
811 // Note: we skip the first string since it can't be repetitive of something at this level
812 for i in 1..replacement_strings.len()-1 {
813 if let Some(bytes) = is_repetitive(&replacement_strings[i-1], &replacement_strings[i]) {
814 replacement_strings[i] = bytes.to_string();
815 }
816 }
817
818 for i in 0..replacement_strings.len() {
819 if replacement_strings[i].contains(PAUSE_AUTO_STR) {
820 let before = if i == 0 {""} else {&replacement_strings[i-1]};
821 let after = if i+1 == replacement_strings.len() {""} else {&replacement_strings[i+1]};
822 replacement_strings[i] = replacement_strings[i].replace(
823 PAUSE_AUTO_STR,
824 &rules_with_context.speech_rules.pref_manager.borrow().get_tts().compute_auto_pause(&rules_with_context.speech_rules.pref_manager.borrow(), before, after));
825 }
826 }
827
828 // join the strings together with spaces in between
829 // concatenation (removal of spaces) is saved for the top level because they otherwise are stripped at the wrong sometimes
830 return Ok( replacement_strings.join(" ") );
831
832 fn is_repetitive<'a>(prev: &str, optional: &'a str) -> Option<&'a str> {
833 // OPTIONAL_INDICATOR surrounds the optional text
834 // minor optimization -- lots of short strings and the OPTIONAL_INDICATOR takes a few bytes, so skip the check for those strings
835 if optional.len() <= 2 * OPTIONAL_INDICATOR_LEN {
836 return None;
837 }
838
839 // should be exactly one match -- ignore more than one for now
840 match optional.find(OPTIONAL_INDICATOR) {
841 None => return None,
842 Some(start_index) => {
843 let optional_word_start_slice = &optional[start_index + OPTIONAL_INDICATOR_LEN..];
844 // now find the end
845 match optional_word_start_slice.find(OPTIONAL_INDICATOR) {
846 None => panic!("Internal error: missing end optional char -- text handling is corrupted!"),

Callers 1

replaceMethod · 0.80

Calls 6

lenMethod · 0.80
is_emptyMethod · 0.80
compute_auto_pauseMethod · 0.80
get_ttsMethod · 0.80
replaceMethod · 0.45
pushMethod · 0.45

Tested by

no test coverage detected