Created
May 1, 2016 14:50
-
-
Save libetl/6e063219d3987278c54c92cc4e27d954 to your computer and use it in GitHub Desktop.
Common Part Finder between two String values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.toilelibre.libe.util; | |
public class CommonPartFinder { | |
private static final int INDEX_NOT_FOUND = -1; | |
private static final String EMPTY = ""; | |
public static class Range { | |
private final int aDiffStart; | |
private final int aDiffEnd; | |
private final int bDiffStart; | |
private final int bDiffEnd; | |
public Range (int aDiffStart, int aDiffEnd, int bDiffStart, int bDiffEnd) { | |
this.aDiffStart = aDiffStart; | |
this.aDiffEnd = aDiffEnd; | |
this.bDiffStart = bDiffStart; | |
this.bDiffEnd = bDiffEnd; | |
} | |
public int getaDiffStart () { | |
return this.aDiffStart; | |
} | |
public int getaDiffEnd () { | |
return this.aDiffEnd; | |
} | |
public int getbDiffStart () { | |
return this.bDiffStart; | |
} | |
public int getbDiffEnd () { | |
return this.bDiffEnd; | |
} | |
} | |
private static String difference (final String str1, final String str2) { | |
if (str1 == null) { | |
return str2; | |
} | |
if (str2 == null) { | |
return str1; | |
} | |
final int at = indexOfDifference (str1, str2); | |
if (at == INDEX_NOT_FOUND) { | |
return EMPTY; | |
} | |
return str2.substring (at); | |
} | |
private static String reverse(final String str) { | |
if (str == null) { | |
return null; | |
} | |
return new StringBuilder(str).reverse().toString(); | |
} | |
private static int indexOfDifference (final CharSequence... css) { | |
if (css == null || css.length <= 1) { | |
return INDEX_NOT_FOUND; | |
} | |
boolean anyStringNull = false; | |
boolean allStringsNull = true; | |
final int arrayLen = css.length; | |
int shortestStrLen = Integer.MAX_VALUE; | |
int longestStrLen = 0; | |
// find the min and max string lengths; this avoids checking to make | |
// sure we are not exceeding the length of the string each time through | |
// the bottom loop. | |
for (int i = 0 ; i < arrayLen ; i++) { | |
if (css [i] == null) { | |
anyStringNull = true; | |
shortestStrLen = 0; | |
} else { | |
allStringsNull = false; | |
shortestStrLen = Math.min (css [i].length (), shortestStrLen); | |
longestStrLen = Math.max (css [i].length (), longestStrLen); | |
} | |
} | |
// handle lists containing all nulls or all empty strings | |
if (allStringsNull || longestStrLen == 0 && !anyStringNull) { | |
return INDEX_NOT_FOUND; | |
} | |
// handle lists containing some nulls or some empty strings | |
if (shortestStrLen == 0) { | |
return 0; | |
} | |
// find the position with the first difference across all strings | |
int firstDiff = INDEX_NOT_FOUND; | |
for (int stringPos = 0 ; stringPos < shortestStrLen ; stringPos++) { | |
final char comparisonChar = css [0].charAt (stringPos); | |
for (int arrayPos = 1 ; arrayPos < arrayLen ; arrayPos++) { | |
if (css [arrayPos].charAt (stringPos) != comparisonChar) { | |
firstDiff = stringPos; | |
break; | |
} | |
} | |
if (firstDiff != INDEX_NOT_FOUND) { | |
break; | |
} | |
} | |
if (firstDiff == -1 && shortestStrLen != longestStrLen) { | |
// we compared all of the characters up to the length of the | |
// shortest string and didn't find a match, but the string lengths | |
// vary, so return the length of the shortest string. | |
return shortestStrLen; | |
} | |
return firstDiff; | |
} | |
private static String intersection(String s1, String s2) { | |
for( int i = Math.min(s1.length(), s2.length()); ; i--) { | |
if(s2.endsWith(s1.substring(0, i))) { | |
return s1.substring(0, i); | |
} | |
} | |
} | |
/** | |
* Input : two string values | |
* Output : | |
* @param a first string | |
* @param b second string | |
* @return a range such as : | |
* - a.subString(0, aDiffStart).equals(b.subString(0, bDiffStart)) and | |
* - a.subString(aDiffEnd).equals(b.subString(bDiffEnd)) | |
*/ | |
public static Range commonPartRanges (String a, String b) { | |
String diff1End = CommonPartFinder.difference (a, b); | |
String diff2End = CommonPartFinder.difference (b, a); | |
String diff1Start = CommonPartFinder.reverse (CommonPartFinder.difference (CommonPartFinder.reverse (a), CommonPartFinder.reverse (b))); | |
String diff2Start = CommonPartFinder.reverse (CommonPartFinder.difference (CommonPartFinder.reverse (b), CommonPartFinder.reverse (a))); | |
String diff1 = CommonPartFinder.intersection (diff1End, diff1Start); | |
String diff2 = CommonPartFinder.intersection (diff2End, diff2Start); | |
return new Range (diff2Start.length () - diff2.length (), | |
diff2Start.length (), | |
diff1Start.length () - diff1.length (), | |
diff1Start.length ()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment