Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-978

Accessing match groups from the closure called by String.replaceAll(regex, closure)

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Closed
    • Minor
    • Resolution: Fixed
    • 1.0-JSR-2
    • 1.0-JSR-3
    • groovy-jdk
    • None

    Description

      The new replaceAll method of String, which takes a closure as a parameter, is
      very handy when some transformation is needed on the found strings other than
      simple replacement. However, the parameter supplied to the closure is the
      found string which isn't helpful when operation on individual groups is
      needed. It would add a great deal of flexibility if individual groups could
      be manipulated as well. The code below is one way to do that. Using
      MatchAccessor as the closure parameter rather than the Matcher itself ensures
      that the closure doesn't mess with the matcher, e.g. by calling reset which
      would result in infinite regress. By overriding toString() and plus() it is
      also convenient to use in string expressions in the closure. (Besides,
      Matchers getAt() calls reset(), which precludes it from being used while
      iterating over the matches).

      I would also vote for having the Matchers getAt method only return groups and
      not reset the matcher. It could then be used in the in Matcher.each without
      going into infinite loop. (The getAt method as it is now, resets the matcher
      and returns the index'th group of the first match if any groups are defined,
      otherwise it returns the index'th match of the whole expression. I suspect
      this latter use case, which is probably the rational for resetting the
      matcher, is somewhat rare.)

      // DefaultGroovyMethods.java

      public String replaceAll(String self, String regex, Closure closure) {
      Matcher matcher = Pattern.compile(regex).matcher(self);
      Match match= new Match(matcher);
      StringBuffer buffer = new StringBuffer();
      while (matcher.find())

      { matcher.appendReplacement(buffer, String.valueOf(closure.call(match))); }

      matcher.appendTail(buffer);
      return buffer.toString();
      }

      public static String getAt(Matcher matcher, int idx)

      { idx = normaliseIndex(idx, matcher.groupCount()); return matcher.group(idx); }

      // Provides access to the current match of a Matcher.
      public static class Match {
      Matcher matcher;

      public Match(Matcher matcher)

      { this.matcher = matcher; }

      public String toString()

      { return matcher.group(0); }

      public Object getAt(int index)

      { index = normaliseIndex(index, matcher.groupCount()); return matcher.group(index); }

      public Object plus(Object object)

      { return matcher.group(0) + object; }

      }

      Attachments

        Activity

          People

            phkim Kim, Pilho
            thor Thorsten Meinl
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Time Tracking

                Estimated:
                Original Estimate - 4h
                4h
                Remaining:
                Remaining Estimate - 4h
                4h
                Logged:
                Time Spent - Not Specified
                Not Specified