Skip to content

Commit b65657e

Browse files
Added test case for kmp algorithm
1 parent 3d00230 commit b65657e

File tree

6 files changed

+96
-29
lines changed

6 files changed

+96
-29
lines changed

strings/single string matching/kmp.go renamed to strings/single-string-matching/kmp/kmp.go

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package main
1+
package kmp
22

33
import (
44
"fmt"
@@ -10,53 +10,65 @@ import (
1010
// User defined.
1111
// Set to true to read input from two command line arguments
1212
// Set to false to read input from two files "pattern.txt" and "text.txt"
13-
const commandLineInput bool = false
13+
const isTakingInputFromCommandLine bool = true
14+
const notFoundPosition int = -1
15+
16+
type result struct {
17+
resultPosition int
18+
numberOfComparison int
19+
}
1420

1521
// Implementation of Knuth-Morris-Pratt algorithm (Prefix based approach).
1622
// Requires either a two command line arguments separated by a single space,
1723
// or two files in the same folder: "pattern.txt" containing the string to
1824
// be searched for, "text.txt" containing the text to be searched in.
1925
func main() {
20-
if commandLineInput == true { // case of command line input
26+
var text string
27+
var word string
28+
29+
if isTakingInputFromCommandLine { // case of command line input
2130
args := os.Args
2231
if len(args) <= 2 {
2332
log.Fatal("Not enough arguments. Two string arguments separated by spaces are required!")
2433
}
25-
pattern := args[1]
26-
s := args[2]
34+
word = args[1]
35+
text = args[2]
2736
for i := 3; i < len(args); i++ {
28-
s = s + " " + args[i]
37+
text = text + " " + args[i]
2938
}
30-
if len(args[1]) > len(s) {
31-
log.Fatal("Pattern is longer than text!")
32-
}
33-
fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n")
34-
fmt.Printf("Search word (%d chars long): %q.\n", len(args[1]), pattern)
35-
fmt.Printf("Text (%d chars long): %q.\n\n", len(s), s)
36-
knp(s, pattern)
37-
} else if commandLineInput == false { // case of file input
38-
patFile, err := ioutil.ReadFile("pattern.txt")
39+
} else { // case of file input
40+
patFile, err := ioutil.ReadFile("../pattern.txt")
3941
if err != nil {
4042
log.Fatal(err)
4143
}
42-
textFile, err := ioutil.ReadFile("text.txt")
44+
textFile, err := ioutil.ReadFile("../text.txt")
4345
if err != nil {
4446
log.Fatal(err)
4547
}
46-
if len(patFile) > len(textFile) {
47-
log.Fatal("Pattern is longer than text!")
48-
}
49-
fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n")
50-
fmt.Printf("Search word (%d chars long): %q.\n", len(patFile), patFile)
51-
fmt.Printf("Text (%d chars long): %q.\n\n", len(textFile), textFile)
52-
knp(string(textFile), string(patFile))
48+
text = string(textFile)
49+
word = string(patFile)
50+
}
51+
52+
if len(word) > len(text) {
53+
log.Fatal("Pattern is longer than text!")
54+
}
55+
fmt.Printf("\nRunning: Knuth-Morris-Pratt algorithm.\n\n")
56+
fmt.Printf("Search word (%d chars long): %q.\n", len(word), word)
57+
fmt.Printf("Text (%d chars long): %q.\n\n", len(text), text)
58+
59+
r := kmp(text, word)
60+
if r.resultPosition == notFoundPosition {
61+
fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", r.numberOfComparison)
62+
} else {
63+
fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", word,
64+
r.resultPosition, text, r.numberOfComparison)
5365
}
5466
}
5567

56-
// Function knp performing the Knuth-Morris-Pratt algorithm.
68+
// Function kmp performing the Knuth-Morris-Pratt algorithm.
5769
// Prints whether the word/pattern was found and on what position in the text or not.
5870
// m - current match in text, i - current character in w, c - amount of comparisons.
59-
func knp(text, word string) {
71+
func kmp(text string, word string) result {
6072
m, i, c := 0, 0, 0
6173
t := kmp_table(word)
6274
for m+i < len(text) {
@@ -65,8 +77,9 @@ func knp(text, word string) {
6577
if word[i] == text[m+i] {
6678
fmt.Printf(" - match")
6779
if i == len(word)-1 {
68-
fmt.Printf("\n\nWord %q was found at position %d in %q. \n%d comparisons were done.", word, m, text, c)
69-
return
80+
return result{
81+
m, c,
82+
}
7083
}
7184
i++
7285
} else {
@@ -78,8 +91,9 @@ func knp(text, word string) {
7891
}
7992
}
8093
}
81-
fmt.Printf("\n\nWord was not found.\n%d comparisons were done.", c)
82-
return
94+
return result{notFoundPosition,
95+
c,
96+
}
8397
}
8498

8599
// Table building alghoritm.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package kmp
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
var testCases = []struct {
9+
name string
10+
word string
11+
text string
12+
expected result
13+
}{
14+
{
15+
"String comparison on single pattern match",
16+
"announce",
17+
"CPM_annual_conference_announce",
18+
result{
19+
22,
20+
32,
21+
},
22+
},
23+
{
24+
"String comparison on multiple pattern match",
25+
"AABA",
26+
"AABAACAADAABAABA",
27+
result{
28+
0,
29+
4,
30+
},
31+
},
32+
{
33+
"String comparison with not found pattern",
34+
"AABC",
35+
"AABAACAADAABAABA",
36+
result{
37+
-1,
38+
23,
39+
},
40+
},
41+
}
42+
43+
func TestKMP(t *testing.T) {
44+
for _, tc := range testCases {
45+
t.Run(tc.name, func(t *testing.T) {
46+
actual := kmp(tc.text, tc.word)
47+
if !reflect.DeepEqual(actual, tc.expected) {
48+
t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v steps at position %v, but actual matches are: %v steps at position %v",
49+
tc.word, tc.text, tc.expected.numberOfComparison, tc.expected.resultPosition, actual.numberOfComparison, actual.resultPosition)
50+
}
51+
})
52+
}
53+
}

0 commit comments

Comments
 (0)