Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions src/main/java/com/company/text/SearchableString.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.company.text;

import java.util.HashMap;
import java.util.Map;

public class SearchableString {
public final String text;
public Map<Integer, Integer> integerIntegerMap;

public SearchableString(String text) {
this.text = text;
}

public int searchText(String textToSearch) {
integerIntegerMap = this.buildIncrementMap(textToSearch);
System.out.println("\nStart to search " + textToSearch + " in " + this.text);
int count = 0;
for (int startIndex = 0; startIndex < text.length() - textToSearch.length() + 1; ) {
int matchedCharCount = 0;
System.out.println("startIndex: " + startIndex);
for (int currIndex = 0; currIndex < textToSearch.length(); ) {
char ch1 = text.charAt(currIndex + startIndex);
char ch2 = textToSearch.charAt(currIndex);
if (ch1 != ch2) {
break;
}
matchedCharCount++;
currIndex++;
}
if (matchedCharCount == textToSearch.length()) {
count++;
System.out.println("all matched in " + startIndex);
startIndex = startIndex + this.integerIntegerMap.get(matchedCharCount);
} else if (matchedCharCount == 0 || matchedCharCount == 1) {
startIndex++;
} else {
startIndex = startIndex + this.integerIntegerMap.get(matchedCharCount);
}
}
return count;
}

/**
* Referencing KMP algorithm
* Build a start-index-increment map when searching text
* Key: length of first matching chars, Value: How many a start index increments.
*
* @param text to build
* @return a start-index-increment map
*/
Map<Integer, Integer> buildIncrementMap(String text) {
System.out.println("IncrementMap build started for " + text);
HashMap<Integer, Integer> incrementMap = new HashMap<>();
for (int startIndex = 1; startIndex < text.length(); ) {
int currentIndex = startIndex;
for (; currentIndex < text.length(); currentIndex++) {
char ch1 = text.charAt(currentIndex - startIndex);
char leftCutText = text.charAt(currentIndex);
int partialMatchingLength = currentIndex + 1;
if (ch1 == leftCutText) {
incrementMap.put(partialMatchingLength, startIndex);
System.out.println("matchedLength: " + partialMatchingLength + " increment: " + startIndex);
} else {
incrementMap.put(currentIndex + 1, 1);
System.out.println("matchedLength: " + partialMatchingLength + " increment: " + 1);
break;
}
}
startIndex = currentIndex + 1;
}
System.out.println("IncrementMap has been built.");
return incrementMap;
}
}
79 changes: 79 additions & 0 deletions src/test/java/com/company/text/SearchableStringTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.company.text;

import org.junit.jupiter.api.Test;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

public class SearchableStringTest {
@Test
public void searchText_whenSearchingAVAInAVAVA_thenReturning2() {
// Given
String textToSearch = "ava";
SearchableString avava = new SearchableString("avava");

// When
int count = avava.searchText(textToSearch);

// Then
assertThat(count).isEqualTo(2);
}

@Test
public void buildIncrementMap_whenAAIsGiven_thenIncrementHasNoElement() {
// Given
String textToSearch = "aa";
SearchableString avava = new SearchableString("");

// When
Map<Integer, Integer> aaIncrementMap = avava.buildIncrementMap(textToSearch);

// Then
assertThat(aaIncrementMap).hasSize(1);
assertThat(aaIncrementMap.get(2)).isEqualTo(1);
}

@Test
public void buildIncrementMap_when_ABcAB_IsGiven() {
// Given
String textToSearch = "abcab";
SearchableString searchableString = new SearchableString("");

// When
Map<Integer, Integer> incrementMap = searchableString.buildIncrementMap(textToSearch);

// Then
assertThat(incrementMap).hasSize(4);
assertThat(incrementMap.get(2)).isEqualTo(1);
assertThat(incrementMap.get(3)).isEqualTo(1);
assertThat(incrementMap.get(4)).isEqualTo(3);
assertThat(incrementMap.get(5)).isEqualTo(3);
}

@Test
public void searchText_whenSearchableTextContainsTheGivenStringIn2SubString_thenReturning2_case1() {
// Given
String textToSearch = "abcabd";
SearchableString searchableString = new SearchableString("XXXX" + textToSearch + "XXXX" + textToSearch);

// When
int matchedCount = searchableString.searchText(textToSearch);

// Then
assertThat(matchedCount).isEqualTo(2);
}

@Test
public void searchText_whenSearchableTextContainsTheGivenStringIn2SubString_thenReturning2_case2() {
// Given
String textToSearch = "abcabd";
SearchableString searchableString = new SearchableString("XXXXabc" + textToSearch + "XXXX" + textToSearch);

// When
int matchedCount = searchableString.searchText(textToSearch);

// Then
assertThat(matchedCount).isEqualTo(2);
}
}