Skip to content

Commit

Permalink
8065554: MatchResult should provide values of named-capturing groups
Browse files Browse the repository at this point in the history
Reviewed-by: smarks
  • Loading branch information
rgiulietti committed Sep 29, 2022
1 parent 1decdce commit ce85cac
Show file tree
Hide file tree
Showing 4 changed files with 619 additions and 52 deletions.
176 changes: 168 additions & 8 deletions src/java.base/share/classes/java/util/regex/MatchResult.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
Expand All @@ -25,6 +25,9 @@

package java.util.regex;

import java.util.Map;
import java.util.Objects;

/**
* The result of a match operation.
*
Expand All @@ -33,6 +36,15 @@
* groups and group boundaries can be seen but not modified through
* a {@code MatchResult}.
*
* @implNote
* Support for named groups is implemented by the default methods
* {@link #start(String)}, {@link #end(String)} and {@link #group(String)}.
* They all make use of the map returned by {@link #namedGroups()}, whose
* default implementation simply throws {@link UnsupportedOperationException}.
* It is thus sufficient to override {@link #namedGroups()} for these methods
* to work. However, overriding them directly might be preferable for
* performance or other reasons.
*
* @author Michael McCloskey
* @see Matcher
* @since 1.5
Expand All @@ -48,7 +60,7 @@ public interface MatchResult {
* If no match has yet been attempted,
* or if the previous match operation failed
*/
public int start();
int start();

/**
* Returns the start index of the subsequence captured by the given group
Expand All @@ -74,7 +86,38 @@ public interface MatchResult {
* If there is no capturing group in the pattern
* with the given index
*/
public int start(int group);
int start(int group);

/**
* Returns the start index of the subsequence captured by the given
* <a href="Pattern.html#groupname">named-capturing group</a> during the
* previous match operation.
*
* @param name
* The name of a named-capturing group in this matcher's pattern
*
* @return The index of the first character captured by the group,
* or {@code -1} if the match was successful but the group
* itself did not match anything
*
* @throws IllegalStateException
* If no match has yet been attempted,
* or if the previous match operation failed
*
* @throws IllegalArgumentException
* If there is no capturing group in the pattern
* with the given name
*
* @implSpec
* The default implementation of this method invokes {@link #namedGroups()}
* to obtain the group number from the {@code name} argument, and uses it
* as argument to an invocation of {@link #start(int)}.
*
* @since 20
*/
default int start(String name) {
return start(groupNumber(name));
}

/**
* Returns the offset after the last character matched.
Expand All @@ -85,7 +128,7 @@ public interface MatchResult {
* If no match has yet been attempted,
* or if the previous match operation failed
*/
public int end();
int end();

/**
* Returns the offset after the last character of the subsequence
Expand All @@ -111,7 +154,38 @@ public interface MatchResult {
* If there is no capturing group in the pattern
* with the given index
*/
public int end(int group);
int end(int group);

/**
* Returns the offset after the last character of the subsequence
* captured by the given <a href="Pattern.html#groupname">named-capturing
* group</a> during the previous match operation.
*
* @param name
* The name of a named-capturing group in this matcher's pattern
*
* @return The offset after the last character captured by the group,
* or {@code -1} if the match was successful
* but the group itself did not match anything
*
* @throws IllegalStateException
* If no match has yet been attempted,
* or if the previous match operation failed
*
* @throws IllegalArgumentException
* If there is no capturing group in the pattern
* with the given name
*
* @implSpec
* The default implementation of this method invokes {@link #namedGroups()}
* to obtain the group number from the {@code name} argument, and uses it
* as argument to an invocation of {@link #end(int)}.
*
* @since 20
*/
default int end(String name) {
return end(groupNumber(name));
}

/**
* Returns the input subsequence matched by the previous match.
Expand All @@ -132,7 +206,7 @@ public interface MatchResult {
* If no match has yet been attempted,
* or if the previous match operation failed
*/
public String group();
String group();

/**
* Returns the input subsequence captured by the given group during the
Expand Down Expand Up @@ -170,7 +244,44 @@ public interface MatchResult {
* If there is no capturing group in the pattern
* with the given index
*/
public String group(int group);
String group(int group);

/**
* Returns the input subsequence captured by the given
* <a href="Pattern.html#groupname">named-capturing group</a> during the
* previous match operation.
*
* <p> If the match was successful but the group specified failed to match
* any part of the input sequence, then {@code null} is returned. Note
* that some groups, for example {@code (a*)}, match the empty string.
* This method will return the empty string when such a group successfully
* matches the empty string in the input. </p>
*
* @param name
* The name of a named-capturing group in this matcher's pattern
*
* @return The (possibly empty) subsequence captured by the named group
* during the previous match, or {@code null} if the group
* failed to match part of the input
*
* @throws IllegalStateException
* If no match has yet been attempted,
* or if the previous match operation failed
*
* @throws IllegalArgumentException
* If there is no capturing group in the pattern
* with the given name
*
* @implSpec
* The default implementation of this method invokes {@link #namedGroups()}
* to obtain the group number from the {@code name} argument, and uses it
* as argument to an invocation of {@link #group(int)}.
*
* @since 20
*/
default String group(String name) {
return group(groupNumber(name));
}

/**
* Returns the number of capturing groups in this match result's pattern.
Expand All @@ -184,6 +295,55 @@ public interface MatchResult {
*
* @return The number of capturing groups in this matcher's pattern
*/
public int groupCount();
int groupCount();

/**
* Returns an unmodifiable map from capturing group names to group numbers.
* If there are no named groups, returns an empty map.
*
* @return an unmodifiable map from capturing group names to group numbers
*
* @throws UnsupportedOperationException if the implementation does not
* support named groups.
*
* @implSpec The default implementation of this method always throws
* {@link UnsupportedOperationException}
*
* @apiNote
* This method must be overridden by an implementation that supports
* named groups.
*
* @since 20
*/
default Map<String,Integer> namedGroups() {
throw new UnsupportedOperationException("namedGroups()");
}

private int groupNumber(String name) {
Objects.requireNonNull(name, "Group name");
Integer number = namedGroups().get(name);
if (number != null) {
return number;
}
throw new IllegalArgumentException("No group with name <" + name + ">");
}

/**
* Returns whether {@code this} contains a valid match from
* a previous match or find operation.
*
* @return whether {@code this} contains a valid match
*
* @throws UnsupportedOperationException if the implementation cannot report
* whether it has a match
*
* @implSpec The default implementation of this method always throws
* {@link UnsupportedOperationException}
*
* @since 20
*/
default boolean hasMatch() {
throw new UnsupportedOperationException("hasMatch()");
}

}

1 comment on commit ce85cac

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.