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>&lt;<i>name</i>&gt; 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);