Fix array index out of bounds error in nu_protocol::value::levenshtein_distance() (#3358)

* Fix array index out of bounds error.

Error occured when computing levenshtein_distance of two strings where
str.len() is not equal to str.chars().collect::<Vec<_>>().len()

* Add test for levenshtein_distance
This commit is contained in:
Jamie Quigley 2021-04-27 20:30:32 +01:00 committed by GitHub
parent f9f74a0f7d
commit 36cc5eb933
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -24,28 +24,28 @@ pub fn did_you_mean(obj_source: &Value, field_tried: String) -> Option<Vec<Strin
/// Borrowed from https://crates.io/crates/natural
fn levenshtein_distance(str1: &str, str2: &str) -> usize {
let n = str1.len();
let m = str2.len();
let mut current: Vec<usize> = (0..str1.len() + 1).collect();
let str1_chars: Vec<char> = str1.chars().collect();
let str2_chars: Vec<char> = str2.chars().collect();
let mut current: Vec<usize> = (0..n + 1).collect();
let a_vec: Vec<char> = str1.chars().collect();
let b_vec: Vec<char> = str2.chars().collect();
let str1_len = str1_chars.len();
let str2_len = str2_chars.len();
for i in 1..m + 1 {
for str2_index in 1..str2_len + 1 {
let previous = current;
current = vec![0; n + 1];
current[0] = i;
for j in 1..n + 1 {
let add = previous[j] + 1;
let delete = current[j - 1] + 1;
let mut change = previous[j - 1];
if a_vec[j - 1] != b_vec[i - 1] {
current = vec![0; str1_len + 1];
current[0] = str2_index;
for str1_index in 1..str1_len + 1 {
let add = previous[str1_index] + 1;
let delete = current[str1_index - 1] + 1;
let mut change = previous[str1_index - 1];
if str1_chars[str1_index - 1] != str2_chars[str2_index - 1] {
change += 1
}
current[j] = min3(add, delete, change);
current[str1_index] = min3(add, delete, change);
}
}
current[n]
current[str1_len]
}
fn min3<T: Ord>(a: T, b: T, c: T) -> T {
@ -91,4 +91,12 @@ mod test {
assert_eq!(None, did_you_mean(&empty_source, "hat".to_string()))
}
#[test]
fn test_levenshtein_distance() {
assert_eq!(super::levenshtein_distance("hello world", "hello world"), 0);
assert_eq!(super::levenshtein_distance("hello", "hello world"), 6);
assert_eq!(super::levenshtein_distance("°C", "°C"), 0);
assert_eq!(super::levenshtein_distance("°", "°C"), 1);
}
}