api/src/main/java/org/ocpsoft/rewrite/util/ParseTools.java
public static CapturingGroup balancedCapture(final char[] chars, final int startPos, final int endPos,
            final CaptureType type)
   {
      Assert.notNull(chars, "Character input array must not be null.");
      Assert.assertTrue(startPos >= 0, "Start position must be greater than zero.");
      Assert.assertTrue(startPos < (chars.length - 1),
               "Start position must be at least one character before the array upper bound.");
      Assert.assertTrue(endPos > 0, "End position must be greater than zero.");
      Assert.assertTrue(endPos < chars.length, "End position must be less than or equal to the array upper bound.");
      Assert.assertTrue(startPos < endPos, "Start position must be less than end position.");

      Assert.assertTrue(chars[startPos] == type.getBegin(), "Character at starting position was [" + chars[startPos]
               + "] but expected [" + type.getBegin() + "]");

      if (isEscaped(chars, startPos))
      {
         throw new IllegalArgumentException(
                  "Character at starting position is escaped, and cannot be used in capturing a group.");
      }

      char begin = type.getBegin();
      char end = type.getEnd();

      int cursor = startPos + 1;
      Stack<Integer> beginPositions = new Stack<Integer>();
      beginPositions.push(cursor);
      while ((cursor <= endPos) && (beginPositions.size() > 0))
      {
         char character = chars[cursor];
         if (character == end)
         {
            if (!isEscaped(chars, cursor))
            {
               beginPositions.pop();
            }
         }
         else if (character == begin)
         {
            if (!isEscaped(chars, cursor))
            {
               beginPositions.push(cursor);
            }
         }

         if (beginPositions.size() == 0)
         {
            break;
         }
         cursor++;
      }

      if (beginPositions.size() > 0)
      {
         throw new IllegalArgumentException(
                  "Unclosed capturing group at index [" + beginPositions.peek() + "] of [" + new String(chars) + "]");
      }

      return new CapturingGroup(chars, startPos, cursor);
   }
public static CapturingGroup balancedCapture(final char[] chars, final int startPos, final int endPos,
            final CaptureType type)
   {
      Assert.notNull(chars, "Character input array must not be null.");
      Assert.assertTrue(startPos >= 0, "Start position must be greater than zero.");
      Assert.assertTrue(startPos < (chars.length - 1),
               "Start position must be at least one character before the array upper bound.");
      Assert.assertTrue(endPos > 0, "End position must be greater than zero.");
      Assert.assertTrue(endPos < chars.length, "End position must be less than or equal to the array upper bound.");
      Assert.assertTrue(startPos < endPos, "Start position must be less than end position.");

      Assert.assertTrue(chars[startPos] == type.getBegin(), "Character at starting position was [" + chars[startPos]
               + "] but expected [" + type.getBegin() + "]");

      if (isEscaped(chars, startPos))
      {
         throw new IllegalArgumentException(
                  "Character at starting position is escaped, and cannot be used in capturing a group.");
      }

      char begin = type.getBegin();
      char end = type.getEnd();

      int cursor = startPos + 1;
      Stack<Integer> beginPositions = new Stack<Integer>();
      beginPositions.push(cursor);
      while ((cursor <= endPos) && (beginPositions.size() > 0))
      {
         char character = chars[cursor];
         if (character == end)
         {
            if (!isEscaped(chars, cursor))
            {
               beginPositions.pop();
            }
         }
         else if (character == begin)
         {
            if (!isEscaped(chars, cursor))
            {
               beginPositions.push(cursor);
            }
         }

         if (beginPositions.size() == 0)
         {
            break;
         }
         cursor++;
      }

      if (beginPositions.size() > 0)
      {
         throw new IllegalArgumentException(
                  "Unclosed capturing group at index [" + beginPositions.peek() + "] of [" + new String(chars) + "]");
      }

      return new CapturingGroup(chars, startPos, cursor);
   }
Return the index of the terminating character in the group, excluding markers.