8312976: MatchResult produces StringIndexOutOfBoundsException for groups outside match
Reviewed-by: alanb, smarks
This commit is contained in:
parent
5d232959c2
commit
61c58fdd00
@ -274,13 +274,40 @@ public final class Matcher implements MatchResult {
|
|||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public MatchResult toMatchResult() {
|
public MatchResult toMatchResult() {
|
||||||
String capturedText = hasMatch()
|
int minStart;
|
||||||
? text.subSequence(first, last).toString()
|
String capturedText;
|
||||||
: null;
|
if (hasMatch()) {
|
||||||
|
minStart = minStart();
|
||||||
|
capturedText = text.subSequence(minStart, maxEnd()).toString();
|
||||||
|
} else {
|
||||||
|
minStart = -1;
|
||||||
|
capturedText = null;
|
||||||
|
}
|
||||||
return new ImmutableMatchResult(first, last, groupCount(),
|
return new ImmutableMatchResult(first, last, groupCount(),
|
||||||
groups.clone(), capturedText,
|
groups.clone(), capturedText,
|
||||||
namedGroups()
|
namedGroups(), minStart);
|
||||||
);
|
}
|
||||||
|
|
||||||
|
private int minStart() {
|
||||||
|
int r = text.length();
|
||||||
|
for (int group = 0; group <= groupCount(); ++group) {
|
||||||
|
int start = groups[group * 2];
|
||||||
|
if (start >= 0) {
|
||||||
|
r = Math.min(r, start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int maxEnd() {
|
||||||
|
int r = 0;
|
||||||
|
for (int group = 0; group <= groupCount(); ++group) {
|
||||||
|
int end = groups[group * 2 + 1];
|
||||||
|
if (end >= 0) {
|
||||||
|
r = Math.max(r, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ImmutableMatchResult implements MatchResult {
|
private static class ImmutableMatchResult implements MatchResult {
|
||||||
@ -290,16 +317,18 @@ public final class Matcher implements MatchResult {
|
|||||||
private final int[] groups;
|
private final int[] groups;
|
||||||
private final String text;
|
private final String text;
|
||||||
private final Map<String, Integer> namedGroups;
|
private final Map<String, Integer> namedGroups;
|
||||||
|
private final int minStart;
|
||||||
|
|
||||||
ImmutableMatchResult(int first, int last, int groupCount,
|
ImmutableMatchResult(int first, int last, int groupCount,
|
||||||
int[] groups, String text,
|
int[] groups, String text,
|
||||||
Map<String, Integer> namedGroups) {
|
Map<String, Integer> namedGroups, int minStart) {
|
||||||
this.first = first;
|
this.first = first;
|
||||||
this.last = last;
|
this.last = last;
|
||||||
this.groupCount = groupCount;
|
this.groupCount = groupCount;
|
||||||
this.groups = groups;
|
this.groups = groups;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.namedGroups = namedGroups;
|
this.namedGroups = namedGroups;
|
||||||
|
this.minStart = minStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -345,7 +374,7 @@ public final class Matcher implements MatchResult {
|
|||||||
checkGroup(group);
|
checkGroup(group);
|
||||||
if ((groups[group * 2] == -1) || (groups[group * 2 + 1] == -1))
|
if ((groups[group * 2] == -1) || (groups[group * 2 + 1] == -1))
|
||||||
return null;
|
return null;
|
||||||
return text.substring(groups[group * 2] - first, groups[group * 2 + 1] - first);
|
return text.substring(groups[group * 2] - minStart, groups[group * 2 + 1] - minStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -23,8 +23,12 @@
|
|||||||
|
|
||||||
import jdk.test.lib.RandomFactory;
|
import jdk.test.lib.RandomFactory;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.regex.MatchResult;
|
import java.util.regex.MatchResult;
|
||||||
@ -33,10 +37,11 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8132995
|
* @bug 8132995 8312976
|
||||||
* @key randomness
|
* @key randomness
|
||||||
*
|
*
|
||||||
* @summary Tests to exercise the optimization described in the bug report.
|
* @summary Tests to exercise the optimization described in the bug report.
|
||||||
@ -179,4 +184,50 @@ public class ImmutableMatchResultTest {
|
|||||||
testResultsStream(CharBuffer.wrap(inResults));
|
testResultsStream(CharBuffer.wrap(inResults));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Arguments[] testGroupsOutsideMatch() {
|
||||||
|
return new Arguments[]{
|
||||||
|
arguments("(?<=(\\d{3}))\\D*(?=(\\d{4}))", "-1234abcxyz5678-"),
|
||||||
|
arguments("(?<=(\\d{3}))\\D*(?=(\\1))", "-1234abcxyz2348-"),
|
||||||
|
arguments("(?<!(\\d{4}))\\D+(?=(\\d{4}))", "123abcxyz5678-"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource
|
||||||
|
void testGroupsOutsideMatch(String pattern, String text) {
|
||||||
|
char[] data = text.toCharArray();
|
||||||
|
Matcher m = Pattern.compile(pattern)
|
||||||
|
.matcher(CharBuffer.wrap(data));
|
||||||
|
|
||||||
|
assertEquals(2, m.groupCount());
|
||||||
|
assertTrue(m.find());
|
||||||
|
|
||||||
|
int start = m.start();
|
||||||
|
int end = m.end();
|
||||||
|
String group = m.group();
|
||||||
|
|
||||||
|
int prefixStart = m.start(1);
|
||||||
|
int prefixEnd = m.end(1);
|
||||||
|
String prefixGroup = m.group(1);
|
||||||
|
|
||||||
|
int suffixStart = m.start(2);
|
||||||
|
int suffixEnd = m.end(2);
|
||||||
|
String suffixGroup = m.group(2);
|
||||||
|
|
||||||
|
MatchResult mr = m.toMatchResult();
|
||||||
|
Arrays.fill(data, '*'); // spoil original input
|
||||||
|
|
||||||
|
assertEquals(start, mr.start());
|
||||||
|
assertEquals(end, mr.end());
|
||||||
|
assertEquals(group, mr.group());
|
||||||
|
|
||||||
|
assertEquals(prefixStart, mr.start(1));
|
||||||
|
assertEquals(prefixEnd, mr.end(1));
|
||||||
|
assertEquals(prefixGroup, mr.group(1));
|
||||||
|
|
||||||
|
assertEquals(suffixStart, mr.start(2));
|
||||||
|
assertEquals(suffixEnd, mr.end(2));
|
||||||
|
assertEquals(suffixGroup, mr.group(2));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user