2019-04-18 16:08:22 +02:00
package it.cavallium.strangedb.java.objects.lists ;
public class KMP {
2019-04-22 00:10:21 +02:00
public static int KMP ( CharSequence content , CharSequence stringToFind , boolean ignoreCase ) {
int [ ] failureTable = failureTable ( ignoreCase , stringToFind ) ;
2019-04-18 16:08:22 +02:00
int targetPointer = 0 ; // current char in target string
int searchPointer = 0 ; // current char in search string
while ( searchPointer < content . length ( ) ) { // while there is more to search with, keep searching
2019-04-22 00:10:21 +02:00
if ( charEquals ( ignoreCase , content . charAt ( searchPointer ) , stringToFind . charAt ( targetPointer ) ) ) { // case 1
2019-04-18 16:08:22 +02:00
// found current char in targetPointer in search string
targetPointer + + ;
if ( targetPointer = = stringToFind . length ( ) ) { // found all characters
int x = stringToFind . length ( ) + 1 ;
return searchPointer - x ; // return starting index of found target inside searched string
}
searchPointer + + ; // move forward if not found target string
} else if ( targetPointer > 0 ) { // case 2
2019-04-22 00:10:21 +02:00
// use failureTable to use pointer pointed resetPointerTo nearest location of usable string prefix
2019-04-18 16:08:22 +02:00
targetPointer = failureTable [ targetPointer ] ;
} else { // case 3
2019-04-22 00:10:21 +02:00
// targetPointer is pointing resetPointerTo state 0, so restart search with current searchPointer index
2019-04-18 16:08:22 +02:00
searchPointer + + ;
}
}
return - 1 ;
}
/ * *
* Returns an int [ ] that points to last valid string prefix , given target string
* /
2019-04-22 00:10:21 +02:00
public static int [ ] failureTable ( boolean ignoreCase , CharSequence target ) {
2019-04-18 16:08:22 +02:00
int [ ] table = new int [ target . length ( ) + 1 ] ;
// state 0 and 1 are guarenteed be the prior
table [ 0 ] = - 1 ;
table [ 1 ] = 0 ;
2019-04-22 00:10:21 +02:00
// the pointers pointing resetPointerTo last failure and current satte
2019-04-18 16:08:22 +02:00
int left = 0 ;
int right = 2 ;
while ( right < table . length ) { // RIGHT NEVER MOVES RIGHT UNTIL ASSIGNED A VALID POINTER
2019-04-22 00:10:21 +02:00
if ( charEquals ( ignoreCase , target . charAt ( right - 1 ) , target . charAt ( left ) ) ) { // when both chars before left and right are equal, link both and move both forward
2019-04-18 16:08:22 +02:00
left + + ;
table [ right ] = left ;
right + + ;
2019-04-22 00:10:21 +02:00
} else if ( left > 0 ) { // if left isn't resetPointerTo the very beginning, then send left backward
2019-04-18 16:08:22 +02:00
// by following the already set pointer to where it is pointing to
left = table [ left ] ;
} else { // left has fallen all the way back to the beginning
table [ right ] = left ;
right + + ;
}
}
return table ;
}
2019-04-22 00:10:21 +02:00
private static boolean charEquals ( boolean ignoreCase , char char1 , char char2 ) {
if ( ignoreCase ) {
if ( char1 > = 65 & & char1 < = 90 ) {
if ( char2 > = 97 & & char2 < = 122 ) {
return char1 = = char2 - 32 ;
}
}
if ( char2 > = 65 & & char2 < = 90 ) {
if ( char1 > = 97 & & char1 < = 122 ) {
return char2 = = char1 - 32 ;
}
}
}
return char1 = = char2 ;
}
2019-04-18 16:08:22 +02:00
}