8303648: Add String.indexOf(String str, int beginIndex, int endIndex)
Reviewed-by: rriggs
This commit is contained in:
parent
c4df9b5f17
commit
4bf1fbb06d
@ -2607,6 +2607,19 @@ public final class String
|
||||
* }</pre>
|
||||
* If no such value of {@code k} exists, then {@code -1} is returned.
|
||||
*
|
||||
* @apiNote
|
||||
* Unlike {@link #substring(int)}, for example, this method does not throw
|
||||
* an exception when {@code fromIndex} is outside the valid range.
|
||||
* Rather, it returns -1 when {@code fromIndex} is larger than the length of
|
||||
* the string.
|
||||
* This result is, by itself, indistinguishable from a genuine absence of
|
||||
* {@code str} in the string.
|
||||
* If stricter behavior is needed, {@link #indexOf(String, int, int)}
|
||||
* should be considered instead.
|
||||
* On {@link String} {@code s} and a non-empty {@code str}, for example,
|
||||
* {@code s.indexOf(str, fromIndex, s.length())} would throw if
|
||||
* {@code fromIndex} were larger than the string length, or were negative.
|
||||
*
|
||||
* @param str the substring to search for.
|
||||
* @param fromIndex the index from which to start the search.
|
||||
* @return the index of the first occurrence of the specified substring,
|
||||
@ -2617,6 +2630,39 @@ public final class String
|
||||
return indexOf(value, coder(), length(), str, fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first occurrence of the specified substring
|
||||
* within the specified index range of {@code this} string.
|
||||
*
|
||||
* <p>This method returns the same result as the one of the invocation
|
||||
* <pre>{@code
|
||||
* s.substring(beginIndex, endIndex).indexOf(str) + beginIndex
|
||||
* }</pre>
|
||||
* if the index returned by {@link #indexOf(String)} is non-negative,
|
||||
* and returns -1 otherwise.
|
||||
* (No substring is instantiated, though.)
|
||||
*
|
||||
* @param str the substring to search for.
|
||||
* @param beginIndex the index to start the search from (included).
|
||||
* @param endIndex the index to stop the search at (excluded).
|
||||
* @return the index of the first occurrence of the specified substring
|
||||
* within the specified index range,
|
||||
* or {@code -1} if there is no such occurrence.
|
||||
* @throws StringIndexOutOfBoundsException if {@code beginIndex}
|
||||
* is negative, or {@code endIndex} is larger than the length of
|
||||
* this {@code String} object, or {@code beginIndex} is larger than
|
||||
* {@code endIndex}.
|
||||
* @since 21
|
||||
*/
|
||||
public int indexOf(String str, int beginIndex, int endIndex) {
|
||||
if (str.length() == 1) {
|
||||
/* Simple optimization, can be omitted without behavioral impact */
|
||||
return indexOf(str.charAt(0), beginIndex, endIndex);
|
||||
}
|
||||
checkBoundsBeginEnd(beginIndex, endIndex, length());
|
||||
return indexOf(value, coder(), endIndex, str, beginIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code shared by String and AbstractStringBuilder to do searches. The
|
||||
* source is the character array being searched, and the target
|
||||
@ -2624,28 +2670,23 @@ public final class String
|
||||
*
|
||||
* @param src the characters being searched.
|
||||
* @param srcCoder the coder of the source string.
|
||||
* @param srcCount length of the source string.
|
||||
* @param srcCount last index (exclusive) in the source string.
|
||||
* @param tgtStr the characters being searched for.
|
||||
* @param fromIndex the index to begin searching from.
|
||||
*/
|
||||
static int indexOf(byte[] src, byte srcCoder, int srcCount,
|
||||
String tgtStr, int fromIndex) {
|
||||
byte[] tgt = tgtStr.value;
|
||||
byte tgtCoder = tgtStr.coder();
|
||||
int tgtCount = tgtStr.length();
|
||||
|
||||
if (fromIndex >= srcCount) {
|
||||
return (tgtCount == 0 ? srcCount : -1);
|
||||
}
|
||||
if (fromIndex < 0) {
|
||||
fromIndex = 0;
|
||||
fromIndex = Math.clamp(fromIndex, 0, srcCount);
|
||||
int tgtCount = tgtStr.length();
|
||||
if (tgtCount > srcCount - fromIndex) {
|
||||
return -1;
|
||||
}
|
||||
if (tgtCount == 0) {
|
||||
return fromIndex;
|
||||
}
|
||||
if (tgtCount > srcCount) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
byte[] tgt = tgtStr.value;
|
||||
byte tgtCoder = tgtStr.coder();
|
||||
if (srcCoder == tgtCoder) {
|
||||
return srcCoder == LATIN1
|
||||
? StringLatin1.indexOf(src, srcCount, tgt, tgtCount, fromIndex)
|
||||
|
@ -29,8 +29,8 @@ import static org.testng.Assert.assertThrows;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8302590
|
||||
* @summary This one is for String.indexOf(int,int,int).
|
||||
* @bug 8302590 8303648
|
||||
* @summary This one is for String.indexOf([int|String],int,int).
|
||||
* @run testng IndexOfBeginEnd
|
||||
*/
|
||||
|
||||
@ -195,6 +195,183 @@ public class IndexOfBeginEnd {
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] resultsStr() {
|
||||
return new Object[][] {
|
||||
|
||||
new Object[] { STRING_EMPTY, "A", 0, 0, -1 },
|
||||
new Object[] { STRING_EMPTY, "", 0, 0, 0 },
|
||||
|
||||
new Object[] { STRING_L1, "A", 0, 1, 0 },
|
||||
new Object[] { STRING_L1, "A", 1, 1, -1 },
|
||||
new Object[] { STRING_L1, "AB", 0, 1, -1 },
|
||||
new Object[] { STRING_L1, "", 0, 0, 0 },
|
||||
new Object[] { STRING_L1, "", 0, 1, 0 },
|
||||
new Object[] { STRING_L1, "", 1, 1, 1 },
|
||||
|
||||
new Object[] { STRING_L2, "A", 0, 2, 0 },
|
||||
new Object[] { STRING_L2, "A", 0, 1, 0 },
|
||||
new Object[] { STRING_L2, "A", 1, 2, -1 },
|
||||
new Object[] { STRING_L2, "B", 0, 2, 1 },
|
||||
new Object[] { STRING_L2, "B", 1, 2, 1 },
|
||||
new Object[] { STRING_L2, "B", 0, 0, -1 },
|
||||
new Object[] { STRING_L2, "AB", 0, 2, 0 },
|
||||
new Object[] { STRING_L2, "AB", 1, 2, -1 },
|
||||
new Object[] { STRING_L2, "AB", 0, 1, -1 },
|
||||
new Object[] { STRING_L2, "", 0, 2, 0 },
|
||||
new Object[] { STRING_L2, "", 1, 2, 1 },
|
||||
new Object[] { STRING_L2, "", 2, 2, 2 },
|
||||
|
||||
new Object[] { STRING_L4, "ABCD", 0, 4, 0 },
|
||||
new Object[] { STRING_L4, "ABCD", 0, 3, -1 },
|
||||
new Object[] { STRING_L4, "ABCD", 1, 4, -1 },
|
||||
new Object[] { STRING_L4, "BC", 0, 4, 1 },
|
||||
new Object[] { STRING_L4, "BC", 0, 3, 1 },
|
||||
new Object[] { STRING_L4, "BC", 1, 4, 1 },
|
||||
new Object[] { STRING_L4, "BC", 1, 2, -1 },
|
||||
new Object[] { STRING_L4, "BC", 2, 4, -1 },
|
||||
new Object[] { STRING_L4, "A", 0, 4, 0 },
|
||||
new Object[] { STRING_L4, "A", 1, 4, -1 },
|
||||
new Object[] { STRING_L4, "CD", 0, 4, 2 },
|
||||
new Object[] { STRING_L4, "CD", 2, 4, 2 },
|
||||
new Object[] { STRING_L4, "CD", 1, 4, 2 },
|
||||
new Object[] { STRING_L4, "CD", 0, 3, -1 },
|
||||
new Object[] { STRING_L4, "A", 2, 4, -1 },
|
||||
new Object[] { STRING_L4, "A", 2, 2, -1 },
|
||||
new Object[] { STRING_L4, "A", 4, 4, -1 },
|
||||
new Object[] { STRING_L4, "ABCDE", 0, 4, -1 },
|
||||
|
||||
new Object[] { STRING_LLONG, "ABCDEFGH", 0, 8, 0 },
|
||||
new Object[] { STRING_LLONG, "ABCDEFGH", 1, 8, -1 },
|
||||
new Object[] { STRING_LLONG, "ABCDEFGH", 0, 7, -1 },
|
||||
new Object[] { STRING_LLONG, "DEFGH", 0, 8, 3 },
|
||||
new Object[] { STRING_LLONG, "DEFGH", 3, 8, 3 },
|
||||
new Object[] { STRING_LLONG, "DEFGH", 4, 8, -1 },
|
||||
new Object[] { STRING_LLONG, "DEFGH", 0, 7, -1 },
|
||||
new Object[] { STRING_LLONG, "A", 0, 8, 0 },
|
||||
new Object[] { STRING_LLONG, "A", 1, 8, -1 },
|
||||
new Object[] { STRING_LLONG, "A", 0, 0, -1 },
|
||||
new Object[] { STRING_LLONG, "GHI", 0, 8, -1 },
|
||||
new Object[] { STRING_LLONG, "GHI", 8, 8, -1 },
|
||||
new Object[] { STRING_LLONG, "", 4, 4, 4 },
|
||||
new Object[] { STRING_LLONG, "", 4, 8, 4 },
|
||||
new Object[] { STRING_LLONG, "", 8, 8, 8 },
|
||||
|
||||
new Object[] { STRING_U1, "\uFF21", 0, 1, 0 },
|
||||
new Object[] { STRING_U1, "\uFF21", 0, 0, -1 },
|
||||
new Object[] { STRING_U1, "\uFF21", 1, 1, -1 },
|
||||
new Object[] { STRING_U1, "\uFF21A", 0, 1, -1 },
|
||||
|
||||
new Object[] { STRING_U2, "\uFF21\uFF22", 0, 2, 0 },
|
||||
new Object[] { STRING_U2, "\uFF21\uFF22", 1, 2, -1 },
|
||||
new Object[] { STRING_U2, "\uFF22", 0, 2, 1 },
|
||||
new Object[] { STRING_U2, "\uFF22", 0, 1, -1 },
|
||||
new Object[] { STRING_U2, "\uFF22", 1, 2, 1 },
|
||||
new Object[] { STRING_U2, "\uFF21", 1, 2, -1 },
|
||||
new Object[] { STRING_U2, "\uFF21", 0, 1, 0 },
|
||||
new Object[] { STRING_U2, "", 0, 1, 0 },
|
||||
new Object[] { STRING_U2, "", 1, 1, 1 },
|
||||
new Object[] { STRING_U2, "", 2, 2, 2 },
|
||||
|
||||
new Object[] { STRING_M12, "\uFF21A", 0, 2, 0 },
|
||||
new Object[] { STRING_M12, "\uFF21A", 0, 1, -1 },
|
||||
new Object[] { STRING_M12, "\uFF21A", 1, 2, -1 },
|
||||
new Object[] { STRING_M12, "A", 1, 2, 1 },
|
||||
new Object[] { STRING_M12, "A", 0, 2, 1 },
|
||||
new Object[] { STRING_M12, "A", 0, 1, -1 },
|
||||
new Object[] { STRING_M12, "\uFF21", 0, 2, 0 },
|
||||
new Object[] { STRING_M12, "\uFF21", 0, 1, 0 },
|
||||
new Object[] { STRING_M12, "\uFF21", 1, 2, -1 },
|
||||
|
||||
new Object[] { STRING_M11, "A\uFF21", 0, 2, 0 },
|
||||
new Object[] { STRING_M11, "\uFF21", 1, 2, 1 },
|
||||
new Object[] { STRING_M11, "A\uFF21", 1, 2, -1 },
|
||||
new Object[] { STRING_M11, "A\uFF21A", 0, 2, -1 },
|
||||
|
||||
new Object[] {
|
||||
STRING_UDUPLICATE,
|
||||
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
|
||||
0, 10, 0 },
|
||||
new Object[] {
|
||||
STRING_UDUPLICATE,
|
||||
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
|
||||
0, 9, -1 },
|
||||
new Object[] {
|
||||
STRING_UDUPLICATE,
|
||||
"\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
|
||||
1, 10, -1 },
|
||||
new Object[] {
|
||||
STRING_UDUPLICATE,
|
||||
"\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
|
||||
1, 10, 1 },
|
||||
new Object[] {
|
||||
STRING_UDUPLICATE,
|
||||
"\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
|
||||
0, 10, 1 },
|
||||
new Object[] {
|
||||
STRING_UDUPLICATE,
|
||||
"\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22\uFF21\uFF22",
|
||||
0, 9, -1 },
|
||||
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22\uFF21\uFF22",
|
||||
4, 10, 4 },
|
||||
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22\uFF21\uFF22",
|
||||
3, 8, 4 },
|
||||
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22\uFF21\uFF22",
|
||||
2, 7, 2 },
|
||||
new Object[] { STRING_UDUPLICATE, "\uFF21\uFF22\uFF21\uFF22",
|
||||
7, 10, -1 },
|
||||
new Object[] { STRING_UDUPLICATE, "",
|
||||
7, 10, 7 },
|
||||
new Object[] { STRING_UDUPLICATE, "",
|
||||
10, 10, 10 },
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] exceptionsStr() {
|
||||
return new Object[][]{
|
||||
new Object[]{STRING_LDUPLICATE, "", -1, 0},
|
||||
new Object[]{STRING_LDUPLICATE, "", 0, 100},
|
||||
new Object[]{STRING_LDUPLICATE, "", -1, 100},
|
||||
new Object[]{STRING_LDUPLICATE, "", 3, 1},
|
||||
|
||||
new Object[]{STRING_UDUPLICATE, "", -1, 0},
|
||||
new Object[]{STRING_UDUPLICATE, "", 0, 100},
|
||||
new Object[]{STRING_UDUPLICATE, "", -1, 100},
|
||||
new Object[]{STRING_UDUPLICATE, "", 3, 1},
|
||||
|
||||
new Object[]{STRING_MDUPLICATE1, "", -1, 0},
|
||||
new Object[]{STRING_MDUPLICATE1, "", 0, 100},
|
||||
new Object[]{STRING_MDUPLICATE1, "", -1, 100},
|
||||
new Object[]{STRING_MDUPLICATE1, "", 3, 1},
|
||||
|
||||
new Object[]{STRING_MDUPLICATE2, "", -1, 0},
|
||||
new Object[]{STRING_MDUPLICATE2, "", 0, 100},
|
||||
new Object[]{STRING_MDUPLICATE2, "", -1, 100},
|
||||
new Object[]{STRING_MDUPLICATE2, "", 3, 1},
|
||||
|
||||
new Object[]{STRING_LDUPLICATE, "A", -1, 0},
|
||||
new Object[]{STRING_LDUPLICATE, "A", 0, 100},
|
||||
new Object[]{STRING_LDUPLICATE, "A", -1, 100},
|
||||
new Object[]{STRING_LDUPLICATE, "A", 3, 1},
|
||||
|
||||
new Object[]{STRING_UDUPLICATE, "A", -1, 0},
|
||||
new Object[]{STRING_UDUPLICATE, "A", 0, 100},
|
||||
new Object[]{STRING_UDUPLICATE, "A", -1, 100},
|
||||
new Object[]{STRING_UDUPLICATE, "A", 3, 1},
|
||||
|
||||
new Object[]{STRING_MDUPLICATE1, "A", -1, 0},
|
||||
new Object[]{STRING_MDUPLICATE1, "A", 0, 100},
|
||||
new Object[]{STRING_MDUPLICATE1, "A", -1, 100},
|
||||
new Object[]{STRING_MDUPLICATE1, "A", 3, 1},
|
||||
|
||||
new Object[]{STRING_MDUPLICATE2, "A", -1, 0},
|
||||
new Object[]{STRING_MDUPLICATE2, "A", 0, 100},
|
||||
new Object[]{STRING_MDUPLICATE2, "A", -1, 100},
|
||||
new Object[]{STRING_MDUPLICATE2, "A", 3, 1},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "results")
|
||||
public void testIndexOf(String str, int ch, int from, int to, int expected) {
|
||||
assertEquals(str.indexOf(ch, from, to), expected,
|
||||
@ -208,6 +385,19 @@ public class IndexOfBeginEnd {
|
||||
() -> str.indexOf(ch, from, to));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "resultsStr")
|
||||
public void testIndexOf(String str, String sub, int from, int to, int expected) {
|
||||
assertEquals(str.indexOf(sub, from, to), expected,
|
||||
String.format("testing String(%s).indexOf(%s,%d,%d)",
|
||||
escapeNonASCIIs(str), escapeNonASCIIs(sub), from, to));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "exceptionsStr")
|
||||
public void testIndexOf(String str, String sub, int from, int to) {
|
||||
assertThrows(StringIndexOutOfBoundsException.class,
|
||||
() -> str.indexOf(sub, from, to));
|
||||
}
|
||||
|
||||
private static String escapeNonASCIIs(String s) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
@ -220,4 +410,5 @@ public class IndexOfBeginEnd {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user