1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use sesdiff::{EditScript,EditInstruction};
use std::str::FromStr;
use std::io::{Error,ErrorKind};

#[derive(Debug)]
pub struct Confusable {
    pub editscript: EditScript<String>,
    pub weight: f64,
    pub strictbegin: bool,
    pub strictend: bool,
}

impl Confusable {
    pub fn new(editscript: &str, weight: f64) -> Result<Confusable,std::io::Error> {
        let strictbegin = editscript.get(0..1).expect("Checking first character") == "^";
        let l = editscript.len();
        let strictend = editscript.get((l - 1)..).expect("Checking last character") == "$";
        Ok(Confusable {
            editscript: if strictbegin && strictend {
                match EditScript::from_str(&editscript[1..l-1]) {
                    Ok(editscript) => editscript,
                    Err(err) => return Err(Error::new(ErrorKind::Other, format!("{:?}",err)))
                }
            } else if strictbegin {
                match EditScript::from_str(&editscript[1..]) {
                    Ok(editscript) => editscript,
                    Err(err) => return Err(Error::new(ErrorKind::Other, format!("{:?}",err)))
                }
            } else if strictend {
                match EditScript::from_str(&editscript[..l-1]) {
                    Ok(editscript) => editscript,
                    Err(err) => return Err(Error::new(ErrorKind::Other, format!("{:?}",err)))
                }
            } else {
                match EditScript::from_str(editscript) {
                    Ok(editscript) => editscript,
                    Err(err) => return Err(Error::new(ErrorKind::Other, format!("{:?}",err)))
                }
            },
            weight: weight,
            strictbegin: strictbegin,
            strictend: strictend,
        })
    }

    ///See if the confusable is found in a larger edit script
    pub fn found_in(&self, refscript: &EditScript<&str>) -> bool {
        let l = self.editscript.instructions.len();
        let mut matches = 0; //number of matching instructions
        for (i, refinstruction) in refscript.instructions.iter().enumerate() {
            if let Some(instruction) = self.editscript.instructions.get(matches) {
                let foundinstruction = match (instruction, refinstruction) {
                    (EditInstruction::Insertion(s), EditInstruction::Insertion(sref)) |  (EditInstruction::Deletion(s), EditInstruction::Deletion(sref)) => {
                        sref.ends_with(s)
                    },
                    (EditInstruction::Identity(s), EditInstruction::Identity(sref)) => {
                        if matches == 0 && matches == l -1 {
                            s == sref
                        } else if matches == 0 {
                            sref.ends_with(s)
                        } else if matches == l - 1 {
                            sref.starts_with(s)
                        } else {
                            s == sref
                        }
                    },
                    (EditInstruction::InsertionOptions(v), EditInstruction::Insertion(sref)) | (EditInstruction::DeletionOptions(v), EditInstruction::Deletion(sref)) => {
                        let mut foundoption = false;
                        for s in v.iter() {
                            if sref.ends_with(s) { foundoption = true; break; }
                        }
                        foundoption
                    },
                    (EditInstruction::IdentityOptions(v), EditInstruction::Identity(sref)) => {
                        let mut foundoption = false;
                        for s in v.iter() {
                            if matches == 0 && matches == l -1 {
                                if s == sref { foundoption = true; break; }
                            } else if matches == 0 {
                                if sref.ends_with(s) { foundoption = true; break; }
                            } else if matches == l - 1 {
                                if sref.starts_with(s) { foundoption = true; break; }
                            } else {
                                if s == sref { foundoption = true; break; }
                            }
                        }
                        foundoption
                    },
                    _ => { false }
                };
                if !foundinstruction {
                    matches = 0;
                    if self.strictbegin {
                        return false;
                    } else {
                        continue; //try again with new reference offset
                    }
                } else {
                    matches += 1;
                    if matches == l {
                        if self.strictend {
                            return i == refscript.instructions.len() - 1;
                        } else {
                            return true;
                        }
                    }
                }
            }
        }
        false
    }
}