implement lastIndexOf

This commit is contained in:
XenoAmess 2020-06-01 01:51:43 +08:00 committed by Rob Tompkins
parent 68cb8af7e4
commit dee8f6fb84
2 changed files with 156 additions and 17 deletions

View File

@ -216,6 +216,8 @@ static int lastIndexOf(final CharSequence cs, final int searchChar, int start) {
return NOT_FOUND;
}
static final int TO_STRING_LIMIT = 16;
/**
* Used by the lastIndexOf(CharSequence methods) as a green implementation of lastIndexOf
*
@ -224,24 +226,66 @@ static int lastIndexOf(final CharSequence cs, final int searchChar, int start) {
* @param start the start index
* @return the index where the search sequence was found
*/
static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, final int start) {
if (cs instanceof String) {
return ((String) cs).lastIndexOf((String) searchChar, start);
} else if (cs instanceof StringBuilder) {
return ((StringBuilder) cs).lastIndexOf((String) searchChar, start);
} else if (cs instanceof StringBuffer) {
return ((StringBuffer) cs).lastIndexOf((String) searchChar, start);
static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, int start) {
if (searchChar instanceof String) {
if (cs instanceof String) {
return ((String) cs).lastIndexOf((String) searchChar, start);
} else if (cs instanceof StringBuilder) {
return ((StringBuilder) cs).lastIndexOf((String) searchChar, start);
} else if (cs instanceof StringBuffer) {
return ((StringBuffer) cs).lastIndexOf((String) searchChar, start);
}
}
return cs.toString().lastIndexOf(searchChar.toString(), start);
// if (cs instanceof String && searchChar instanceof String) {
// // TODO: Do we assume searchChar is usually relatively small;
// // If so then calling toString() on it is better than reverting to
// // the green implementation in the else block
// return ((String) cs).lastIndexOf((String) searchChar, start);
// } else {
// // TODO: Implement rather than convert to String
// return cs.toString().lastIndexOf(searchChar.toString(), start);
// }
int len1 = cs.length();
int len2 = searchChar.length();
if (start > len1) {
start = len1;
}
if (start < 0 || len2 < 0 || len2 > len1) {
return -1;
}
if (len2 == 0) {
return start;
}
if (len2 <= TO_STRING_LIMIT) {
if (cs instanceof String) {
return ((String) cs).lastIndexOf(searchChar.toString(), start);
} else if (cs instanceof StringBuilder) {
return ((StringBuilder) cs).lastIndexOf(searchChar.toString(), start);
} else if (cs instanceof StringBuffer) {
return ((StringBuffer) cs).lastIndexOf(searchChar.toString(), start);
}
}
if (start + len2 > len1) {
start = len1 - len2;
}
if (check(cs, searchChar, len2, start)) {
return start;
}
for (int i = start - 1; i >= 0; i--) {
if (check(cs, searchChar, len2, i)) {
return i;
}
}
return -1;
}
private static boolean check(final CharSequence cs, final CharSequence searchChar, int len2, int start1) {
for (int i = 0; i < len2; i++) {
if (cs.charAt(start1 + i) != searchChar.charAt(i)) {
return false;
}
}
return true;
}
/**

View File

@ -16,6 +16,7 @@
*/
package org.apache.commons.lang3;
import static java.nio.CharBuffer.wrap;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@ -26,7 +27,11 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.nio.CharBuffer;
import java.util.Random;
import java.util.stream.IntStream;
import org.apache.commons.lang3.text.StrBuilder;
import org.junit.jupiter.api.Test;
/**
@ -186,4 +191,94 @@ public void testToCharArray() {
assertArrayEquals(expected, CharSequenceUtils.toCharArray(builder.toString()));
}
static class WrapperString implements CharSequence {
CharSequence inner;
public WrapperString(CharSequence inner) {
this.inner = inner;
}
@Override
public int length() {
return inner.length();
}
@Override
public char charAt(int index) {
return inner.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return inner.subSequence(start, end);
}
@Override
public String toString() {
return inner.toString();
}
@Override
public IntStream chars() {
return inner.chars();
}
@Override
public IntStream codePoints() {
return inner.codePoints();
}
}
@Test
public void testNewLastIndexOf() {
testNewLastIndexOfSingle("808087847-1321060740-635567660180086727-925755305", "-1321060740-635567660", 21);
testNewLastIndexOfSingle("", "");
testNewLastIndexOfSingle("1", "");
testNewLastIndexOfSingle("", "1");
testNewLastIndexOfSingle("1", "1");
testNewLastIndexOfSingle("11", "1");
testNewLastIndexOfSingle("1", "11");
Random random = new Random();
StringBuilder seg = new StringBuilder();
while (seg.length() <= CharSequenceUtils.TO_STRING_LIMIT) {
seg.append(random.nextInt());
}
StringBuilder original = new StringBuilder(seg);
testNewLastIndexOfSingle(original, seg);
for (int i = 0; i < 100; i++) {
if (random.nextDouble() < 0.5) {
original.append(random.nextInt() % 10);
} else {
original = new StringBuilder().append(String.valueOf(random.nextInt() % 100)).append(original);
}
testNewLastIndexOfSingle(original, seg);
}
}
private void testNewLastIndexOfSingle(CharSequence a, CharSequence b) {
int maxa = Math.max(a.length(), b.length());
for (int i = -maxa-10; i <= maxa+10; i++) {
testNewLastIndexOfSingle(a, b, i);
}
}
private void testNewLastIndexOfSingle(CharSequence a, CharSequence b, int start) {
testNewLastIndexOfSingleSingle(a, b, start);
testNewLastIndexOfSingleSingle(b, a, start);
}
private void testNewLastIndexOfSingleSingle(CharSequence a, CharSequence b, int start) {
int expected = a.toString().lastIndexOf(b.toString(), start);
// assertEquals(
// expected,
// lastIndexOf(new WrapperString(a), b, start),
// "testNewLastIndexOf fails! original : " + a + " seg : " + b + " start : " + start
// );
assertEquals(
expected,
CharSequenceUtils.lastIndexOf(new WrapperString(a.toString()), b.toString(), start),
"testNewLastIndexOf fails! original : " + a + " seg : " + b + " start : " + start
);
}
}