src/share/classes/java/util/regex/Matcher.java
Print this page
@@ -489,10 +489,49 @@
return null;
return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
}
/**
+ * 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 <tt>null</tt> is returned. Note
+ * that some groups, for example <tt>(a*)</tt>, 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 <tt>null</tt> 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
+ */
+ public String group(String name) {
+ if (name == null)
+ throw new NullPointerException("Null group name");
+ if (first < 0)
+ throw new IllegalStateException("No match found");
+ if (!parentPattern.namedGroups().containsKey(name))
+ throw new IllegalArgumentException("No group with name <" + name + ">");
+ int group = parentPattern.namedGroups().get(name);
+ if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
+ return null;
+ return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
+ }
+
+ /**
* Returns the number of capturing groups in this matcher's pattern.
*
* <p> Group zero denotes the entire pattern by convention. It is not
* included in this count.
*
@@ -647,13 +686,15 @@
*
* </ol>
*
* <p> The replacement string may contain references to subsequences
* captured during the previous match: Each occurrence of
- * <tt>$</tt><i>g</i><tt></tt> will be replaced by the result of
- * evaluating {@link #group(int) group}<tt>(</tt><i>g</i><tt>)</tt>.
- * The first number after the <tt>$</tt> is always treated as part of
+ * <tt>$</tt><<i>name</i>> or <tt>$</tt><i>g</i>
+ * will be replaced by the result of evaluating the corresponding
+ * {@link #group(String) group(name)} or {@link #group(int) group(g)</tt>}
+ * respectively. For <tt>$</tt><i>g</i><tt></tt>,
+ * the first number after the <tt>$</tt> is always treated as part of
* the group reference. Subsequent numbers are incorporated into g if
* they would form a legal group reference. Only the numerals '0'
* through '9' are considered as potential components of the group
* reference. If the second group matched the string <tt>"foo"</tt>, for
* example, then passing the replacement string <tt>"$2bar"</tt> would
@@ -693,10 +734,14 @@
*
* @throws IllegalStateException
* If no match has yet been attempted,
* or if the previous match operation failed
*
+ * @throws IllegalArgumentException
+ * If the replacement string refers to a named-capturing
+ * group that does not exist in the pattern
+ *
* @throws IndexOutOfBoundsException
* If the replacement string refers to a capturing group
* that does not exist in the pattern
*/
public Matcher appendReplacement(StringBuffer sb, String replacement) {
@@ -717,17 +762,49 @@
result.append(nextChar);
cursor++;
} else if (nextChar == '$') {
// Skip past $
cursor++;
+ // A StringIndexOutOfBoundsException is thrown if
+ // this "$" is the last character in replacement
+ // string in current implementation, a IAE might be
+ // more appropriate.
+ nextChar = replacement.charAt(cursor);
+ int refNum = -1;
+ if (nextChar == '<') {
+ cursor++;
+ StringBuilder gsb = new StringBuilder();
+ while (cursor < replacement.length()) {
+ nextChar = replacement.charAt(cursor);
+ if (ASCII.isLower(nextChar) ||
+ ASCII.isUpper(nextChar) ||
+ ASCII.isDigit(nextChar)) {
+ gsb.append(nextChar);
+ cursor++;
+ } else {
+ break;
+ }
+ }
+ if (gsb.length() == 0)
+ throw new IllegalArgumentException(
+ "named capturing group has 0 length name");
+ if (nextChar != '>')
+ throw new IllegalArgumentException(
+ "named capturing group is missing trailing '>'");
+ String gname = gsb.toString();
+ if (!parentPattern.namedGroups().containsKey(gname))
+ throw new IllegalArgumentException(
+ "No group with name <" + gname + ">");
+ refNum = parentPattern.namedGroups().get(gname);
+ cursor++;
+ } else {
// The first number is always a group
- int refNum = (int)replacement.charAt(cursor) - '0';
+ refNum = (int)nextChar - '0';
if ((refNum < 0)||(refNum > 9))
throw new IllegalArgumentException(
"Illegal group reference");
cursor++;
-
// Capture the largest legal group string
boolean done = false;
while (!done) {
if (cursor >= replacement.length()) {
break;
@@ -742,10 +819,11 @@
} else {
refNum = newRefNum;
cursor++;
}
}
+ }
// Append group
if (start(refNum) != -1 && end(refNum) != -1)
result.append(text, start(refNum), end(refNum));
} else {
result.append(nextChar);