8065554: MatchResult should provide values of named-capturing groups

Reviewed-by: smarks
This commit is contained in:
Raffaello Giulietti 2022-09-29 09:16:21 +00:00
parent 1decdcee71
commit ce85cac947
4 changed files with 619 additions and 52 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package java.util.regex;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Spliterator;
@ -229,6 +230,8 @@ public final class Matcher implements MatchResult {
*/
int modCount;
private Map<String, Integer> namedGroups;
/**
* No default constructor.
*/
@ -278,7 +281,8 @@ public final class Matcher implements MatchResult {
this.last,
groupCount(),
this.groups.clone(),
text);
text,
namedGroups());
}
private static class ImmutableMatchResult implements MatchResult {
@ -287,15 +291,18 @@ public final class Matcher implements MatchResult {
private final int[] groups;
private final int groupCount;
private final String text;
private final Map<String, Integer> namedGroups;
ImmutableMatchResult(int first, int last, int groupCount,
int[] groups, String text)
int[] groups, String text,
Map<String, Integer> namedGroups)
{
this.first = first;
this.last = last;
this.groupCount = groupCount;
this.groups = groups;
this.text = text;
this.namedGroups = namedGroups;
}
@Override
@ -307,8 +314,7 @@ public final class Matcher implements MatchResult {
@Override
public int start(int group) {
checkMatch();
if (group < 0 || group > groupCount)
throw new IndexOutOfBoundsException("No group " + group);
checkGroup(group);
return groups[group * 2];
}
@ -321,8 +327,7 @@ public final class Matcher implements MatchResult {
@Override
public int end(int group) {
checkMatch();
if (group < 0 || group > groupCount)
throw new IndexOutOfBoundsException("No group " + group);
checkGroup(group);
return groups[group * 2 + 1];
}
@ -340,18 +345,33 @@ public final class Matcher implements MatchResult {
@Override
public String group(int group) {
checkMatch();
if (group < 0 || group > groupCount)
throw new IndexOutOfBoundsException("No group " + group);
if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
checkGroup(group);
if ((groups[group * 2] == -1) || (groups[group * 2 + 1] == -1))
return null;
return text.subSequence(groups[group * 2], groups[group * 2 + 1]).toString();
}
@Override
public Map<String, Integer> namedGroups() {
return namedGroups;
}
@Override
public boolean hasMatch() {
return first >= 0;
}
private void checkGroup(int group) {
if (group < 0 || group > groupCount)
throw new IndexOutOfBoundsException("No group " + group);
}
private void checkMatch() {
if (first < 0)
if (!hasMatch())
throw new IllegalStateException("No match found");
}
}
/**
@ -446,8 +466,7 @@ public final class Matcher implements MatchResult {
* or if the previous match operation failed
*/
public int start() {
if (first < 0)
throw new IllegalStateException("No match available");
checkMatch();
return first;
}
@ -476,10 +495,8 @@ public final class Matcher implements MatchResult {
* with the given index
*/
public int start(int group) {
if (first < 0)
throw new IllegalStateException("No match available");
if (group < 0 || group > groupCount())
throw new IndexOutOfBoundsException("No group " + group);
checkMatch();
checkGroup(group);
return groups[group * 2];
}
@ -518,8 +535,7 @@ public final class Matcher implements MatchResult {
* or if the previous match operation failed
*/
public int end() {
if (first < 0)
throw new IllegalStateException("No match available");
checkMatch();
return last;
}
@ -548,10 +564,8 @@ public final class Matcher implements MatchResult {
* with the given index
*/
public int end(int group) {
if (first < 0)
throw new IllegalStateException("No match available");
if (group < 0 || group > groupCount())
throw new IndexOutOfBoundsException("No group " + group);
checkMatch();
checkGroup(group);
return groups[group * 2 + 1];
}
@ -640,10 +654,8 @@ public final class Matcher implements MatchResult {
* with the given index
*/
public String group(int group) {
if (first < 0)
throw new IllegalStateException("No match found");
if (group < 0 || group > groupCount())
throw new IndexOutOfBoundsException("No group " + group);
checkMatch();
checkGroup(group);
if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
return null;
return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
@ -900,9 +912,7 @@ public final class Matcher implements MatchResult {
* that does not exist in the pattern
*/
public Matcher appendReplacement(StringBuffer sb, String replacement) {
// If no match, return error
if (first < 0)
throw new IllegalStateException("No match available");
checkMatch();
StringBuilder result = new StringBuilder();
appendExpandedReplacement(replacement, result);
// Append the intervening text
@ -991,8 +1001,7 @@ public final class Matcher implements MatchResult {
*/
public Matcher appendReplacement(StringBuilder sb, String replacement) {
// If no match, return error
if (first < 0)
throw new IllegalStateException("No match available");
checkMatch();
StringBuilder result = new StringBuilder();
appendExpandedReplacement(replacement, result);
// Append the intervening text
@ -1055,10 +1064,10 @@ public final class Matcher implements MatchResult {
throw new IllegalArgumentException(
"capturing group name {" + gname +
"} starts with digit character");
if (!parentPattern.namedGroups().containsKey(gname))
if (!namedGroups().containsKey(gname))
throw new IllegalArgumentException(
"No group with name {" + gname + "}");
refNum = parentPattern.namedGroups().get(gname);
refNum = namedGroups().get(gname);
cursor++;
} else {
// The first number is always a group
@ -1796,10 +1805,47 @@ public final class Matcher implements MatchResult {
*/
int getMatchedGroupIndex(String name) {
Objects.requireNonNull(name, "Group name");
if (first < 0)
throw new IllegalStateException("No match found");
if (!parentPattern.namedGroups().containsKey(name))
checkMatch();
if (!namedGroups().containsKey(name))
throw new IllegalArgumentException("No group with name <" + name + ">");
return parentPattern.namedGroups().get(name);
return namedGroups().get(name);
}
private void checkGroup(int group) {
if (group < 0 || group > groupCount())
throw new IndexOutOfBoundsException("No group " + group);
}
private void checkMatch() {
if (!hasMatch())
throw new IllegalStateException("No match found");
}
/**
* {@inheritDoc}
*
* @return {@inheritDoc}
*
* @since {@inheritDoc}
*/
@Override
public Map<String, Integer> namedGroups() {
if (namedGroups == null) {
return namedGroups = parentPattern.namedGroups();
}
return namedGroups;
}
/**
* {@inheritDoc}
*
* @return {@inheritDoc}
*
* @since {@inheritDoc}
*/
@Override
public boolean hasMatch() {
return first >= 0;
}
}