Add ability to specify user-defined functions for matcher
This commit is contained in:
+8
-7
@@ -4,20 +4,21 @@ use std::cmp;
|
||||
|
||||
|
||||
pub struct Differ {
|
||||
linejunk: Option<String>,
|
||||
charjunk: Option<String>
|
||||
pub line_junk: Option<fn(&str) -> bool>,
|
||||
pub char_junk: Option<fn(&str) -> bool>
|
||||
}
|
||||
|
||||
impl Differ{
|
||||
pub fn new() -> Differ {
|
||||
Differ{
|
||||
linejunk: None,
|
||||
charjunk: None
|
||||
line_junk: None,
|
||||
char_junk: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compare<T: ?Sized + Sequence>(&self, first_sequence: &T, second_sequence: &T) -> Vec<String> {
|
||||
let mut matcher = SequenceMatcher::new(first_sequence, second_sequence);
|
||||
matcher.set_is_junk(self.line_junk);
|
||||
let mut res = Vec::new();
|
||||
for opcode in matcher.get_opcodes(){
|
||||
let mut gen = Vec::new();
|
||||
@@ -87,7 +88,7 @@ impl Differ{
|
||||
continue;
|
||||
}
|
||||
let mut cruncher = SequenceMatcher::new(first_sequence_str, second_sequence_str);
|
||||
//cruncher.charjunk = self.charjunk;
|
||||
cruncher.set_is_junk(self.char_junk);
|
||||
if cruncher.ratio() > best_ratio{
|
||||
best_ratio = cruncher.ratio();
|
||||
best_i = i;
|
||||
@@ -97,7 +98,7 @@ impl Differ{
|
||||
}
|
||||
if best_ratio < cutoff{
|
||||
if eqi.is_none(){
|
||||
//res.extend(self.plain_replace(first_sequence, first_start, first_end, second_sequence, second_start, second_end).iter().cloned());
|
||||
res.extend(self.plain_replace(first_sequence, first_start, first_end, second_sequence, second_start, second_end).iter().cloned());
|
||||
return res
|
||||
}
|
||||
best_i = eqi.unwrap();
|
||||
@@ -111,7 +112,7 @@ impl Differ{
|
||||
if eqi.is_none(){
|
||||
let (mut first_tag, mut second_tag) = (String::new(), String::new());
|
||||
let mut cruncher = SequenceMatcher::new(first_element, second_element);
|
||||
//cruncher.charjunk = self.charjunk;
|
||||
cruncher.set_is_junk(self.char_junk);
|
||||
for opcode in &cruncher.get_opcodes(){
|
||||
let (first_length, second_length) = (opcode.first_end - opcode.first_start, opcode.second_end - opcode.second_start);
|
||||
match opcode.tag.as_ref() {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ use utils::{format_range_unified, format_range_context};
|
||||
|
||||
pub fn get_close_matches<'a>(word: &str, possibilities: Vec<&'a str>, n: usize, cutoff: f32) -> Vec<&'a str> {
|
||||
if !(0.0 <= cutoff && cutoff <= 1.0) {
|
||||
//error
|
||||
panic!("Cutoff must be greater than 0.0 and lower than 1.0");
|
||||
}
|
||||
let mut res: Vec<(f32, &str)> = Vec::new();
|
||||
let mut matcher = SequenceMatcher::new("", word);
|
||||
|
||||
+24
-20
@@ -44,7 +44,6 @@ impl Opcode{
|
||||
pub trait Sequence: Debug {
|
||||
fn len(&self) -> usize;
|
||||
fn at_index(&self, index: usize) -> Option<&str>;
|
||||
fn slice(&self, start: usize, end: usize) -> Option<&str>;
|
||||
}
|
||||
|
||||
impl Sequence for str {
|
||||
@@ -52,20 +51,13 @@ impl Sequence for str {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn slice(&self, start: usize, end: usize) -> Option<&str> {
|
||||
if start >= end{
|
||||
return None
|
||||
}
|
||||
if start > self.len() || end > self.len(){
|
||||
return None
|
||||
}
|
||||
unsafe{
|
||||
Some(self.slice_unchecked(start, end))
|
||||
}
|
||||
}
|
||||
|
||||
fn at_index(&self, index: usize) -> Option<&str> {
|
||||
self.slice(index, index + 1)
|
||||
if index > self.len(){
|
||||
return None
|
||||
}
|
||||
unsafe{
|
||||
Some(self.slice_unchecked(index, index + 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,10 +66,6 @@ impl<'a> Sequence for Vec<&'a str> {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn slice(&self, start: usize, end: usize) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn at_index(&self, index: usize) -> Option<&str> {
|
||||
if index < self.len() && index >= 0 {
|
||||
return Some(self[index])
|
||||
@@ -91,7 +79,7 @@ pub struct SequenceMatcher<'a, T: 'a + ?Sized + Sequence>{
|
||||
second_sequence: &'a T,
|
||||
matching_blocks: Option<Vec<Match>>,
|
||||
opcodes: Option<Vec<Opcode>>,
|
||||
autojunk: bool,
|
||||
is_junk: Option<fn(&str) -> bool>,
|
||||
second_sequence_elements: HashMap<&'a str, Vec<usize>>,
|
||||
second_sequence_popular: Vec<&'a str>
|
||||
}
|
||||
@@ -105,7 +93,7 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T>{
|
||||
second_sequence: second_sequence,
|
||||
matching_blocks: None,
|
||||
opcodes: None,
|
||||
autojunk: true,
|
||||
is_junk: None,
|
||||
second_sequence_elements: HashMap::new(),
|
||||
second_sequence_popular: Vec::new()
|
||||
};
|
||||
@@ -113,6 +101,11 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T>{
|
||||
matcher
|
||||
}
|
||||
|
||||
pub fn set_is_junk(&mut self, is_junk: Option<fn(&str) -> bool>) {
|
||||
self.is_junk = is_junk;
|
||||
self.set_second_seq(self.second_sequence);
|
||||
}
|
||||
|
||||
pub fn set_seqs(&mut self, first_sequence: &'a T, second_sequence: &'a T) {
|
||||
self.set_first_seq(first_sequence);
|
||||
self.set_second_seq(second_sequence);
|
||||
@@ -138,6 +131,17 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T>{
|
||||
let mut counter = second_sequence_elements.entry(second_sequence.at_index(i).unwrap()).or_insert(Vec::new());
|
||||
counter.push(i);
|
||||
}
|
||||
if self.is_junk.is_some() {
|
||||
let mut junk = Vec::new();
|
||||
for element in second_sequence_elements.keys() {
|
||||
if (self.is_junk.unwrap())(element) {
|
||||
junk.push(element.clone());
|
||||
}
|
||||
}
|
||||
for element in &junk {
|
||||
second_sequence_elements.remove(element);
|
||||
}
|
||||
}
|
||||
let mut popular = Vec::new();
|
||||
let len = second_sequence.len();
|
||||
if len >= 200 {
|
||||
|
||||
@@ -27,7 +27,6 @@ pub fn count_leading(line: &str, c: char) -> usize {
|
||||
|
||||
pub fn format_range_unified(start:usize, end: usize) -> String {
|
||||
let mut beginning = start + 1;
|
||||
println!("{:?} {}", start, end);
|
||||
let length = end - start;
|
||||
if length == 1 {
|
||||
return beginning.to_string()
|
||||
|
||||
+18
-1
@@ -102,9 +102,26 @@ fn test_differ_compare() {
|
||||
assert_eq!(result, "- one\n? ^\n+ ore\n? ^\n- two\n- three\n? -\n+ tree\n+ emu\n");
|
||||
}
|
||||
|
||||
fn is_junk_char(ch: &str) -> bool {
|
||||
if ch == " " || ch == "\t" {
|
||||
return true
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_differ_compare_with_func() {
|
||||
let first_text = vec!["one\n", "two\n", "three\n"];
|
||||
let second_text = vec!["ore\n", "tree\n", "emu\n"];
|
||||
let mut differ = Differ::new();
|
||||
differ.char_junk = Some(is_junk_char);
|
||||
let result = differ.compare(&first_text, &second_text).join("");
|
||||
assert_eq!(result, "- one\n? ^\n+ ore\n? ^\n- two\n- three\n? -\n+ tree\n+ emu\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_differ_restore() {
|
||||
let first_text = vec!["one\n", "two\n", "three\n"];
|
||||
let first_text = vec!["one\n", " two\n", "three\n"];
|
||||
let second_text = vec!["ore\n", "tree\n", "emu\n"];
|
||||
let differ = Differ::new();
|
||||
let diff = differ.compare(&first_text, &second_text);
|
||||
|
||||
Reference in New Issue
Block a user