11/*
2- * Copyright (c) 2003, 2013 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2003, 2022 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2525
2626package java .util .regex ;
2727
28+ import java .util .Map ;
29+ import java .util .Objects ;
30+
2831/**
2932 * The result of a match operation.
3033 *
3336 * groups and group boundaries can be seen but not modified through
3437 * a {@code MatchResult}.
3538 *
39+ * @implNote
40+ * Support for named groups is implemented by the default methods
41+ * {@link #start(String)}, {@link #end(String)} and {@link #group(String)}.
42+ * They all make use of the map returned by {@link #namedGroups()}, whose
43+ * default implementation simply throws {@link UnsupportedOperationException}.
44+ * It is thus sufficient to override {@link #namedGroups()} for these methods
45+ * to work. However, overriding them directly might be preferable for
46+ * performance or other reasons.
47+ *
3648 * @author Michael McCloskey
3749 * @see Matcher
3850 * @since 1.5
@@ -48,7 +60,7 @@ public interface MatchResult {
4860 * If no match has yet been attempted,
4961 * or if the previous match operation failed
5062 */
51- public int start ();
63+ int start ();
5264
5365 /**
5466 * Returns the start index of the subsequence captured by the given group
@@ -74,7 +86,38 @@ public interface MatchResult {
7486 * If there is no capturing group in the pattern
7587 * with the given index
7688 */
77- public int start (int group );
89+ int start (int group );
90+
91+ /**
92+ * Returns the start index of the subsequence captured by the given
93+ * <a href="Pattern.html#groupname">named-capturing group</a> during the
94+ * previous match operation.
95+ *
96+ * @param name
97+ * The name of a named-capturing group in this matcher's pattern
98+ *
99+ * @return The index of the first character captured by the group,
100+ * or {@code -1} if the match was successful but the group
101+ * itself did not match anything
102+ *
103+ * @throws IllegalStateException
104+ * If no match has yet been attempted,
105+ * or if the previous match operation failed
106+ *
107+ * @throws IllegalArgumentException
108+ * If there is no capturing group in the pattern
109+ * with the given name
110+ *
111+ * @implSpec
112+ * The default implementation of this method invokes {@link #namedGroups()}
113+ * to obtain the group number from the {@code name} argument, and uses it
114+ * as argument to an invocation of {@link #start(int)}.
115+ *
116+ * @since 20
117+ */
118+ default int start (String name ) {
119+ return start (groupNumber (name ));
120+ }
78121
79122 /**
80123 * Returns the offset after the last character matched.
@@ -85,7 +128,7 @@ public interface MatchResult {
85128 * If no match has yet been attempted,
86129 * or if the previous match operation failed
87130 */
88- public int end ();
131+ int end ();
89132
90133 /**
91134 * Returns the offset after the last character of the subsequence
@@ -111,7 +154,38 @@ public interface MatchResult {
111154 * If there is no capturing group in the pattern
112155 * with the given index
113156 */
114- public int end (int group );
157+ int end (int group );
158+
159+ /**
160+ * Returns the offset after the last character of the subsequence
161+ * captured by the given <a href="Pattern.html#groupname">named-capturing
162+ * group</a> during the previous match operation.
163+ *
164+ * @param name
165+ * The name of a named-capturing group in this matcher's pattern
166+ *
167+ * @return The offset after the last character captured by the group,
168+ * or {@code -1} if the match was successful
169+ * but the group itself did not match anything
170+ *
171+ * @throws IllegalStateException
172+ * If no match has yet been attempted,
173+ * or if the previous match operation failed
174+ *
175+ * @throws IllegalArgumentException
176+ * If there is no capturing group in the pattern
177+ * with the given name
178+ *
179+ * @implSpec
180+ * The default implementation of this method invokes {@link #namedGroups()}
181+ * to obtain the group number from the {@code name} argument, and uses it
182+ * as argument to an invocation of {@link #end(int)}.
183+ *
184+ * @since 20
185+ */
186+ default int end (String name ) {
187+ return end (groupNumber (name ));
188+ }
115189
116190 /**
117191 * Returns the input subsequence matched by the previous match.
@@ -132,7 +206,7 @@ public interface MatchResult {
132206 * If no match has yet been attempted,
133207 * or if the previous match operation failed
134208 */
135- public String group ();
209+ String group ();
136210
137211 /**
138212 * Returns the input subsequence captured by the given group during the
@@ -170,7 +244,44 @@ public interface MatchResult {
170244 * If there is no capturing group in the pattern
171245 * with the given index
172246 */
173- public String group (int group );
247+ String group (int group );
248+
249+ /**
250+ * Returns the input subsequence captured by the given
251+ * <a href="Pattern.html#groupname">named-capturing group</a> during the
252+ * previous match operation.
253+ *
254+ * <p> If the match was successful but the group specified failed to match
255+ * any part of the input sequence, then {@code null} is returned. Note
256+ * that some groups, for example {@code (a*)}, match the empty string.
257+ * This method will return the empty string when such a group successfully
258+ * matches the empty string in the input. </p>
259+ *
260+ * @param name
261+ * The name of a named-capturing group in this matcher's pattern
262+ *
263+ * @return The (possibly empty) subsequence captured by the named group
264+ * during the previous match, or {@code null} if the group
265+ * failed to match part of the input
266+ *
267+ * @throws IllegalStateException
268+ * If no match has yet been attempted,
269+ * or if the previous match operation failed
270+ *
271+ * @throws IllegalArgumentException
272+ * If there is no capturing group in the pattern
273+ * with the given name
274+ *
275+ * @implSpec
276+ * The default implementation of this method invokes {@link #namedGroups()}
277+ * to obtain the group number from the {@code name} argument, and uses it
278+ * as argument to an invocation of {@link #group(int)}.
279+ *
280+ * @since 20
281+ */
282+ default String group (String name ) {
283+ return group (groupNumber (name ));
284+ }
174285
175286 /**
176287 * Returns the number of capturing groups in this match result's pattern.
@@ -184,6 +295,55 @@ public interface MatchResult {
184295 *
185296 * @return The number of capturing groups in this matcher's pattern
186297 */
187- public int groupCount ();
298+ int groupCount ();
299+
300+ /**
301+ * Returns an unmodifiable map from capturing group names to group numbers.
302+ * If there are no named groups, returns an empty map.
303+ *
304+ * @return an unmodifiable map from capturing group names to group numbers
305+ *
306+ * @throws UnsupportedOperationException if the implementation does not
307+ * support named groups.
308+ *
309+ * @implSpec The default implementation of this method always throws
310+ * {@link UnsupportedOperationException}
311+ *
312+ * @apiNote
313+ * This method must be overridden by an implementation that supports
314+ * named groups.
315+ *
316+ * @since 20
317+ */
318+ default Map <String ,Integer > namedGroups () {
319+ throw new UnsupportedOperationException ("namedGroups()" );
320+ }
321+
322+ private int groupNumber (String name ) {
323+ Objects .requireNonNull (name , "Group name" );
324+ Integer number = namedGroups ().get (name );
325+ if (number != null ) {
326+ return number ;
327+ }
328+ throw new IllegalArgumentException ("No group with name <" + name + ">" );
329+ }
330+
331+ /**
332+ * Returns whether {@code this} contains a valid match from
333+ * a previous match or find operation.
334+ *
335+ * @return whether {@code this} contains a valid match
336+ *
337+ * @throws UnsupportedOperationException if the implementation cannot report
338+ * whether it has a match
339+ *
340+ * @implSpec The default implementation of this method always throws
341+ * {@link UnsupportedOperationException}
342+ *
343+ * @since 20
344+ */
345+ default boolean hasMatch () {
346+ throw new UnsupportedOperationException ("hasMatch()" );
347+ }
188348
189349}
0 commit comments