Skip to content

Commit ce85cac

Browse files
committedSep 29, 2022
8065554: MatchResult should provide values of named-capturing groups
Reviewed-by: smarks
1 parent 1decdce commit ce85cac

File tree

4 files changed

+619
-52
lines changed

4 files changed

+619
-52
lines changed
 

‎src/java.base/share/classes/java/util/regex/MatchResult.java

+168-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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
@@ -25,6 +25,9 @@
2525

2626
package java.util.regex;
2727

28+
import java.util.Map;
29+
import java.util.Objects;
30+
2831
/**
2932
* The result of a match operation.
3033
*
@@ -33,6 +36,15 @@
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

Comments
 (0)
Please sign in to comment.