Make SequenceMatcher generic over all slice types
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "difflib"
|
name = "difflib"
|
||||||
version = "0.3.1"
|
version = "0.4.0"
|
||||||
authors = ["Dima Kudosh <dimakudosh@gmail.com>"]
|
authors = ["Dima Kudosh <dimakudosh@gmail.com>"]
|
||||||
description = "Port of Python's difflib library to Rust."
|
description = "Port of Python's difflib library to Rust."
|
||||||
documentation = "https://github.com/DimaKudosh/difflib/wiki"
|
documentation = "https://github.com/DimaKudosh/difflib/wiki"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Simply add difflib to your dependencies block in Cargo.toml
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
[dependencies]
|
[dependencies]
|
||||||
difflib = "0.3.0"
|
difflib = "0.4.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
@@ -65,7 +65,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//SequenceMatcher examples
|
//SequenceMatcher examples
|
||||||
let mut matcher = SequenceMatcher::new("one two three four", "zero one tree four");
|
let mut matcher = SequenceMatcher::new(b"one two three four", b"zero one tree four");
|
||||||
let m = matcher.find_longest_match(0, 18, 0, 18);
|
let m = matcher.find_longest_match(0, 18, 0, 18);
|
||||||
println!("{:?}", m);
|
println!("{:?}", m);
|
||||||
let all_matches = matcher.get_matching_blocks();
|
let all_matches = matcher.get_matching_blocks();
|
||||||
@@ -76,7 +76,7 @@ fn main() {
|
|||||||
println!("{:?}", grouped_opcodes);
|
println!("{:?}", grouped_opcodes);
|
||||||
let ratio = matcher.ratio();
|
let ratio = matcher.ratio();
|
||||||
println!("{:?}", ratio);
|
println!("{:?}", ratio);
|
||||||
matcher.set_seqs("aaaaa", "aaaab");
|
matcher.set_seqs(b"aaaaa", b"aaaab");
|
||||||
println!("{:?}", matcher.ratio());
|
println!("{:?}", matcher.ratio());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
+2
-2
@@ -47,7 +47,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//SequenceMatcher examples
|
//SequenceMatcher examples
|
||||||
let mut matcher = SequenceMatcher::new("one two three four", "zero one tree four");
|
let mut matcher = SequenceMatcher::new(b"one two three four", b"zero one tree four");
|
||||||
let m = matcher.find_longest_match(0, 18, 0, 18);
|
let m = matcher.find_longest_match(0, 18, 0, 18);
|
||||||
println!("{:?}", m);
|
println!("{:?}", m);
|
||||||
let all_matches = matcher.get_matching_blocks();
|
let all_matches = matcher.get_matching_blocks();
|
||||||
@@ -58,6 +58,6 @@ fn main() {
|
|||||||
println!("{:?}", grouped_opcodes);
|
println!("{:?}", grouped_opcodes);
|
||||||
let ratio = matcher.ratio();
|
let ratio = matcher.ratio();
|
||||||
println!("{:?}", ratio);
|
println!("{:?}", ratio);
|
||||||
matcher.set_seqs("aaaaa", "aaaab");
|
matcher.set_seqs(b"aaaaa", b"aaaab");
|
||||||
println!("{:?}", matcher.ratio());
|
println!("{:?}", matcher.ratio());
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-4
@@ -4,8 +4,8 @@ use utils::{count_leading, str_with_similar_chars};
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Differ {
|
pub struct Differ {
|
||||||
pub line_junk: Option<fn(&str) -> bool>,
|
pub line_junk: Option<fn(&&str) -> bool>,
|
||||||
pub char_junk: Option<fn(&str) -> bool>,
|
pub char_junk: Option<fn(&char) -> bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Differ {
|
impl Differ {
|
||||||
@@ -123,7 +123,12 @@ impl Differ {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let mut cruncher = SequenceMatcher::new(*first_sequence_str, *second_sequence_str);
|
let (first_sequence_chars, second_sequence_chars) = (
|
||||||
|
first_sequence_str.chars().collect::<Vec<char>>(),
|
||||||
|
second_sequence_str.chars().collect::<Vec<char>>(),
|
||||||
|
);
|
||||||
|
let mut cruncher =
|
||||||
|
SequenceMatcher::new(&first_sequence_chars, &second_sequence_chars);
|
||||||
cruncher.set_is_junk(self.char_junk);
|
cruncher.set_is_junk(self.char_junk);
|
||||||
if cruncher.ratio() > best_ratio {
|
if cruncher.ratio() > best_ratio {
|
||||||
best_ratio = cruncher.ratio();
|
best_ratio = cruncher.ratio();
|
||||||
@@ -167,7 +172,9 @@ impl Differ {
|
|||||||
let second_element = &second_sequence[best_j];
|
let second_element = &second_sequence[best_j];
|
||||||
if eqi.is_none() {
|
if eqi.is_none() {
|
||||||
let (mut first_tag, mut second_tag) = (String::new(), String::new());
|
let (mut first_tag, mut second_tag) = (String::new(), String::new());
|
||||||
let mut cruncher = SequenceMatcher::new(*first_element, second_element);
|
let first_element_chars: Vec<char> = first_element.chars().collect();
|
||||||
|
let second_element_chars: Vec<char> = second_element.chars().collect();
|
||||||
|
let mut cruncher = SequenceMatcher::new(&first_element_chars, &second_element_chars);
|
||||||
cruncher.set_is_junk(self.char_junk);
|
cruncher.set_is_junk(self.char_junk);
|
||||||
for opcode in &cruncher.get_opcodes() {
|
for opcode in &cruncher.get_opcodes() {
|
||||||
let (first_length, second_length) = (
|
let (first_length, second_length) = (
|
||||||
|
|||||||
+39
-26
@@ -4,6 +4,7 @@ mod utils;
|
|||||||
|
|
||||||
use sequencematcher::{Sequence, SequenceMatcher};
|
use sequencematcher::{Sequence, SequenceMatcher};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Display;
|
||||||
use utils::{format_range_context, format_range_unified};
|
use utils::{format_range_context, format_range_unified};
|
||||||
|
|
||||||
pub fn get_close_matches<'a>(
|
pub fn get_close_matches<'a>(
|
||||||
@@ -16,9 +17,9 @@ pub fn get_close_matches<'a>(
|
|||||||
panic!("Cutoff must be greater than 0.0 and lower than 1.0");
|
panic!("Cutoff must be greater than 0.0 and lower than 1.0");
|
||||||
}
|
}
|
||||||
let mut res: Vec<(f32, &str)> = Vec::new();
|
let mut res: Vec<(f32, &str)> = Vec::new();
|
||||||
let mut matcher = SequenceMatcher::new("", word);
|
let mut matcher = SequenceMatcher::new(b"", word.as_bytes());
|
||||||
for i in &possibilities {
|
for i in &possibilities {
|
||||||
matcher.set_first_seq(i);
|
matcher.set_first_seq(i.as_bytes());
|
||||||
let ratio = matcher.ratio();
|
let ratio = matcher.ratio();
|
||||||
if ratio >= cutoff {
|
if ratio >= cutoff {
|
||||||
res.push((ratio, i));
|
res.push((ratio, i));
|
||||||
@@ -29,9 +30,9 @@ pub fn get_close_matches<'a>(
|
|||||||
res.iter().map(|x| x.1).collect()
|
res.iter().map(|x| x.1).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unified_diff<T: Sequence>(
|
pub fn unified_diff<T: Sequence + Display>(
|
||||||
first_sequence: &T,
|
first_sequence: &[T],
|
||||||
second_sequence: &T,
|
second_sequence: &[T],
|
||||||
from_file: &str,
|
from_file: &str,
|
||||||
to_file: &str,
|
to_file: &str,
|
||||||
from_file_date: &str,
|
from_file_date: &str,
|
||||||
@@ -59,19 +60,31 @@ pub fn unified_diff<T: Sequence>(
|
|||||||
));
|
));
|
||||||
for code in group {
|
for code in group {
|
||||||
if code.tag == "equal" {
|
if code.tag == "equal" {
|
||||||
for i in code.first_start..code.first_end {
|
for item in first_sequence
|
||||||
res.push(format!(" {}", first_sequence.at_index(i).unwrap()));
|
.iter()
|
||||||
|
.take(code.first_end)
|
||||||
|
.skip(code.first_start)
|
||||||
|
{
|
||||||
|
res.push(format!(" {}", item));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if code.tag == "replace" || code.tag == "delete" {
|
if code.tag == "replace" || code.tag == "delete" {
|
||||||
for i in code.first_start..code.first_end {
|
for item in first_sequence
|
||||||
res.push(format!("-{}", first_sequence.at_index(i).unwrap()));
|
.iter()
|
||||||
|
.take(code.first_end)
|
||||||
|
.skip(code.first_start)
|
||||||
|
{
|
||||||
|
res.push(format!("-{}", item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if code.tag == "replace" || code.tag == "insert" {
|
if code.tag == "replace" || code.tag == "insert" {
|
||||||
for i in code.second_start..code.second_end {
|
for item in second_sequence
|
||||||
res.push(format!("+{}", second_sequence.at_index(i).unwrap()));
|
.iter()
|
||||||
|
.take(code.second_end)
|
||||||
|
.skip(code.second_start)
|
||||||
|
{
|
||||||
|
res.push(format!("+{}", item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,9 +92,9 @@ pub fn unified_diff<T: Sequence>(
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn context_diff<T: Sequence>(
|
pub fn context_diff<T: Sequence + Display>(
|
||||||
first_sequence: &T,
|
first_sequence: &[T],
|
||||||
second_sequence: &T,
|
second_sequence: &[T],
|
||||||
from_file: &str,
|
from_file: &str,
|
||||||
to_file: &str,
|
to_file: &str,
|
||||||
from_file_date: &str,
|
from_file_date: &str,
|
||||||
@@ -119,12 +132,12 @@ pub fn context_diff<T: Sequence>(
|
|||||||
if any {
|
if any {
|
||||||
for opcode in group {
|
for opcode in group {
|
||||||
if opcode.tag != "insert" {
|
if opcode.tag != "insert" {
|
||||||
for i in opcode.first_start..opcode.first_end {
|
for item in first_sequence
|
||||||
res.push(format!(
|
.iter()
|
||||||
"{}{}",
|
.take(opcode.first_end)
|
||||||
&prefix[&opcode.tag],
|
.skip(opcode.first_start)
|
||||||
first_sequence.at_index(i).unwrap()
|
{
|
||||||
));
|
res.push(format!("{}{}", &prefix[&opcode.tag], item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,12 +154,12 @@ pub fn context_diff<T: Sequence>(
|
|||||||
if any {
|
if any {
|
||||||
for opcode in group {
|
for opcode in group {
|
||||||
if opcode.tag != "delete" {
|
if opcode.tag != "delete" {
|
||||||
for i in opcode.second_start..opcode.second_end {
|
for item in second_sequence
|
||||||
res.push(format!(
|
.iter()
|
||||||
"{}{}",
|
.take(opcode.second_end)
|
||||||
&prefix[&opcode.tag],
|
.skip(opcode.second_start)
|
||||||
second_sequence.at_index(i).unwrap()
|
{
|
||||||
));
|
res.push(format!("{}{}", prefix[&opcode.tag], item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-90
@@ -1,6 +1,6 @@
|
|||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::hash::Hash;
|
||||||
use utils::calculate_ratio;
|
use utils::calculate_ratio;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
|
||||||
@@ -47,87 +47,20 @@ impl Opcode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Sequence: Debug {
|
pub trait Sequence: Eq + Hash {}
|
||||||
fn len(&self) -> usize;
|
impl<T: Eq + Hash> Sequence for T {}
|
||||||
fn at_index(&self, index: usize) -> Option<&str>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sequence for str {
|
pub struct SequenceMatcher<'a, T: 'a + Sequence> {
|
||||||
fn len(&self) -> usize {
|
first_sequence: &'a [T],
|
||||||
self.len()
|
second_sequence: &'a [T],
|
||||||
}
|
|
||||||
|
|
||||||
fn at_index(&self, index: usize) -> Option<&str> {
|
|
||||||
if index > self.len() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
unsafe { Some(self.slice_unchecked(index, index + 1)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Sequence for Vec<&'a str> {
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn at_index(&self, index: usize) -> Option<&str> {
|
|
||||||
if index < self.len() {
|
|
||||||
return Some(self[index]);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sequence for String {
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn at_index(&self, index: usize) -> Option<&str> {
|
|
||||||
if index > self.len() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
unsafe { Some(self.slice_unchecked(index, index + 1)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Sequence for Vec<String> {
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn at_index(&self, index: usize) -> Option<&str> {
|
|
||||||
if index < self.len() {
|
|
||||||
return Some(&self[index]);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Sequence for [&'a str] {
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn at_index(&self, index: usize) -> Option<&str> {
|
|
||||||
if index < self.len() {
|
|
||||||
return Some(self[index]);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SequenceMatcher<'a, T: 'a + ?Sized + Sequence> {
|
|
||||||
first_sequence: &'a T,
|
|
||||||
second_sequence: &'a T,
|
|
||||||
matching_blocks: Option<Vec<Match>>,
|
matching_blocks: Option<Vec<Match>>,
|
||||||
opcodes: Option<Vec<Opcode>>,
|
opcodes: Option<Vec<Opcode>>,
|
||||||
is_junk: Option<fn(&str) -> bool>,
|
is_junk: Option<fn(&T) -> bool>,
|
||||||
second_sequence_elements: HashMap<&'a str, Vec<usize>>,
|
second_sequence_elements: HashMap<&'a T, Vec<usize>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
|
impl<'a, T: Sequence> SequenceMatcher<'a, T> {
|
||||||
pub fn new(first_sequence: &'a T, second_sequence: &'a T) -> SequenceMatcher<'a, T> {
|
pub fn new(first_sequence: &'a [T], second_sequence: &'a [T]) -> SequenceMatcher<'a, T> {
|
||||||
let mut matcher = SequenceMatcher {
|
let mut matcher = SequenceMatcher {
|
||||||
first_sequence,
|
first_sequence,
|
||||||
second_sequence,
|
second_sequence,
|
||||||
@@ -140,23 +73,23 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
|
|||||||
matcher
|
matcher
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_is_junk(&mut self, is_junk: Option<fn(&str) -> bool>) {
|
pub fn set_is_junk(&mut self, is_junk: Option<fn(&T) -> bool>) {
|
||||||
self.is_junk = is_junk;
|
self.is_junk = is_junk;
|
||||||
self.set_second_seq(self.second_sequence);
|
self.set_second_seq(self.second_sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_seqs(&mut self, first_sequence: &'a T, second_sequence: &'a T) {
|
pub fn set_seqs(&mut self, first_sequence: &'a [T], second_sequence: &'a [T]) {
|
||||||
self.set_first_seq(first_sequence);
|
self.set_first_seq(first_sequence);
|
||||||
self.set_second_seq(second_sequence);
|
self.set_second_seq(second_sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_first_seq(&mut self, sequence: &'a T) {
|
pub fn set_first_seq(&mut self, sequence: &'a [T]) {
|
||||||
self.first_sequence = sequence;
|
self.first_sequence = sequence;
|
||||||
self.matching_blocks = None;
|
self.matching_blocks = None;
|
||||||
self.opcodes = None;
|
self.opcodes = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_second_seq(&mut self, sequence: &'a T) {
|
pub fn set_second_seq(&mut self, sequence: &'a [T]) {
|
||||||
self.second_sequence = sequence;
|
self.second_sequence = sequence;
|
||||||
self.matching_blocks = None;
|
self.matching_blocks = None;
|
||||||
self.opcodes = None;
|
self.opcodes = None;
|
||||||
@@ -166,9 +99,9 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
|
|||||||
fn chain_second_seq(&mut self) {
|
fn chain_second_seq(&mut self) {
|
||||||
let second_sequence = self.second_sequence;
|
let second_sequence = self.second_sequence;
|
||||||
let mut second_sequence_elements = HashMap::new();
|
let mut second_sequence_elements = HashMap::new();
|
||||||
for i in 0..second_sequence.len() {
|
for (i, item) in second_sequence.iter().enumerate() {
|
||||||
let mut counter = second_sequence_elements
|
let mut counter = second_sequence_elements
|
||||||
.entry(second_sequence.at_index(i).unwrap())
|
.entry(item)
|
||||||
.or_insert_with(Vec::new);
|
.or_insert_with(Vec::new);
|
||||||
counter.push(i);
|
counter.push(i);
|
||||||
}
|
}
|
||||||
@@ -202,10 +135,14 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
|
|||||||
let second_sequence_elements = &self.second_sequence_elements;
|
let second_sequence_elements = &self.second_sequence_elements;
|
||||||
let (mut best_i, mut best_j, mut best_size) = (first_start, second_start, 0);
|
let (mut best_i, mut best_j, mut best_size) = (first_start, second_start, 0);
|
||||||
let mut j2len: HashMap<usize, usize> = HashMap::new();
|
let mut j2len: HashMap<usize, usize> = HashMap::new();
|
||||||
for i in first_start..first_end {
|
for (i, item) in first_sequence
|
||||||
let mut new_j2len: HashMap<usize, usize> = HashMap::new();
|
.iter()
|
||||||
if let Some(indexes) = second_sequence_elements.get(first_sequence.at_index(i).unwrap())
|
.enumerate()
|
||||||
|
.take(first_end)
|
||||||
|
.skip(first_start)
|
||||||
{
|
{
|
||||||
|
let mut new_j2len: HashMap<usize, usize> = HashMap::new();
|
||||||
|
if let Some(indexes) = second_sequence_elements.get(item) {
|
||||||
for j in indexes {
|
for j in indexes {
|
||||||
let j = *j;
|
let j = *j;
|
||||||
if j < second_start {
|
if j < second_start {
|
||||||
@@ -234,15 +171,15 @@ impl<'a, T: ?Sized + Sequence> SequenceMatcher<'a, T> {
|
|||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
while best_i > first_start
|
while best_i > first_start
|
||||||
&& best_j > second_start
|
&& best_j > second_start
|
||||||
&& first_sequence.at_index(best_i - 1) == second_sequence.at_index(best_j - 1)
|
&& first_sequence.get(best_i - 1) == second_sequence.get(best_j - 1)
|
||||||
{
|
{
|
||||||
best_i -= 1;
|
best_i -= 1;
|
||||||
best_j -= 1;
|
best_j -= 1;
|
||||||
best_size += 1;
|
best_size += 1;
|
||||||
}
|
}
|
||||||
while best_i + best_size < first_end && best_j + best_size < second_end
|
while best_i + best_size < first_end
|
||||||
&& first_sequence.at_index(best_i + best_size)
|
&& best_j + best_size < second_end
|
||||||
== second_sequence.at_index(best_j + best_size)
|
&& first_sequence.get(best_i + best_size) == second_sequence.get(best_j + best_size)
|
||||||
{
|
{
|
||||||
best_size += 1;
|
best_size += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -5,7 +5,7 @@ use difflib::sequencematcher::{Match, Opcode, SequenceMatcher};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_longest_match() {
|
fn test_longest_match() {
|
||||||
let matcher = SequenceMatcher::new(" abcd", "abcd abcd");
|
let matcher = SequenceMatcher::new(b" abcd", b"abcd abcd");
|
||||||
let m = matcher.find_longest_match(0, 5, 0, 9);
|
let m = matcher.find_longest_match(0, 5, 0, 9);
|
||||||
assert_eq!(m.first_start, 0);
|
assert_eq!(m.first_start, 0);
|
||||||
assert_eq!(m.second_start, 4);
|
assert_eq!(m.second_start, 4);
|
||||||
@@ -14,7 +14,7 @@ fn test_longest_match() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_all_matches() {
|
fn test_all_matches() {
|
||||||
let mut matcher = SequenceMatcher::new("abxcd", "abcd");
|
let mut matcher = SequenceMatcher::new(b"abxcd", b"abcd");
|
||||||
let result = matcher.get_matching_blocks();
|
let result = matcher.get_matching_blocks();
|
||||||
let mut expected_result = Vec::new();
|
let mut expected_result = Vec::new();
|
||||||
expected_result.push(Match {
|
expected_result.push(Match {
|
||||||
@@ -37,7 +37,7 @@ fn test_all_matches() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_opcodes() {
|
fn test_get_opcodes() {
|
||||||
let mut matcher = SequenceMatcher::new("qabxcd", "abycdf");
|
let mut matcher = SequenceMatcher::new(b"qabxcd", b"abycdf");
|
||||||
let result = matcher.get_opcodes();
|
let result = matcher.get_opcodes();
|
||||||
let mut expected_result = Vec::new();
|
let mut expected_result = Vec::new();
|
||||||
expected_result.push(Opcode {
|
expected_result.push(Opcode {
|
||||||
@@ -80,7 +80,7 @@ fn test_get_opcodes() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ratio() {
|
fn test_ratio() {
|
||||||
let mut matcher = SequenceMatcher::new("abcd", "bcde");
|
let mut matcher = SequenceMatcher::new(b"abcd", b"bcde");
|
||||||
assert_eq!(matcher.ratio(), 0.75);
|
assert_eq!(matcher.ratio(), 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,8 +103,8 @@ fn test_differ_compare() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_junk_char(ch: &str) -> bool {
|
fn is_junk_char(ch: &char) -> bool {
|
||||||
if ch == " " || ch == "\t" {
|
if *ch == ' ' || *ch == '\t' {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
|||||||
Reference in New Issue
Block a user