Skip to content

Commit

Permalink
Merge pull request #7 from w-henderson/krauss-fix
Browse files Browse the repository at this point in the history
Fixed bug in Krauss' algorithm implementation
  • Loading branch information
w-henderson authored Oct 7, 2021
2 parents 69ffb27 + 779e240 commit 8f05aec
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 17 deletions.
2 changes: 1 addition & 1 deletion humphrey/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "humphrey"
version = "0.1.2"
version = "0.1.3"
edition = "2018"
license = "MIT"
homepage = "https://github.com/w-henderson/Humphrey"
Expand Down
31 changes: 16 additions & 15 deletions humphrey/src/krauss.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
use std::iter::Peekable;
use std::str::Chars;

/// Checks whether a wild string (a string possibly containing wildcards) matches a tame string (a string with no wildcards).
///
/// Uses Krauss' algorithm, which you can read more about
/// [here](https://www.drdobbs.com/architecture-and-design/matching-wildcards-an-algorithm/210200888).
pub fn wildcard_match(wild: &str, tame: &str) -> bool {
let mut wild_iter = wild.chars();
let mut tame_iter = tame.chars();
let mut after_last_wild: Option<Chars> = None;

let mut tame_char = tame_iter.next();
let mut wild_char = wild_iter.next();
let mut wild_iter: Peekable<Chars> = wild.chars().peekable();
let mut tame_iter: Peekable<Chars> = tame.chars().peekable();
let mut after_last_wild: Option<Peekable<Chars>> = None;

loop {
let tame_char = tame_iter.peek().copied();
let wild_char = wild_iter.peek().copied();

if tame_char.is_none() {
// If the tame string is finished and so far matches

Expand All @@ -24,7 +25,7 @@ pub fn wildcard_match(wild: &str, tame: &str) -> bool {
// If the wild string still has a wildcard character, this could match zero characters
// Move on to the next wildcard character and run this section again since `tame_char` will still be `None`
// For example, "abc" matches "abc*"
wild_char = wild_iter.next();
wild_iter.next();
continue;
}

Expand All @@ -41,14 +42,14 @@ pub fn wildcard_match(wild: &str, tame: &str) -> bool {
if wild_char == Some('*') {
// If the wild character is a wildcard character, store the position after it
// This is needed in cases such as "abcd" matching "a*d"
let mut new_after_last_wild = wild_iter.clone();
new_after_last_wild.next();
after_last_wild = Some(new_after_last_wild);
wild_iter.next();
after_last_wild = Some(wild_iter.clone());
continue;
} else if let Some(after_last_wild_iter) = &after_last_wild {
// If there is not a new wildcard character, but there has previously been one, move the iterator to
// immediately after the last wildcard character, and store the next character.
wild_iter = after_last_wild_iter.clone();
wild_char = wild_iter.next();
let wild_char = wild_iter.peek().copied();

if wild_char.is_none() {
// If there are no more wild characters, this means that the last character of the wild string was a
Expand All @@ -58,10 +59,10 @@ pub fn wildcard_match(wild: &str, tame: &str) -> bool {
} else if tame_char == wild_char {
// If the characters do match, the end of the wildcard segment must have been reached, so increment the
// iterator.
wild_char = wild_iter.next();
wild_iter.next();
}

tame_char = tame_iter.next();
tame_iter.next();
continue;
} else {
// If the characters do not match, are not wildcard, do not follow a wildcard, and do not complete a wildcard
Expand All @@ -71,7 +72,7 @@ pub fn wildcard_match(wild: &str, tame: &str) -> bool {
}
}

tame_char = tame_iter.next();
wild_char = wild_iter.next();
tame_iter.next();
wild_iter.next();
}
}
4 changes: 3 additions & 1 deletion humphrey/src/tests/krauss.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#[allow(unused_imports)]
use crate::krauss::wildcard_match;

#[test]
Expand All @@ -24,6 +23,9 @@ fn test_match() {
assert!(wildcard_match("*cd*", "abcd"));
assert!(wildcard_match("*cd*", "cdef"));
assert!(wildcard_match("*cd*", "abcdef"));
assert!(!wildcard_match("*ab", "abc"));
assert!(!wildcard_match("a*f", "abcd"));
assert!(!wildcard_match("a*f", "cdef"));

// Just matches
assert!(wildcard_match("*", "ab"));
Expand Down

0 comments on commit 8f05aec

Please sign in to comment.