public static CharSequence replaceGroupsWithMatchDataInCaptures(@NotNull CharSequence string,
                                                                  @NotNull StringWithId matchingString,
                                                                  @NotNull MatchData matchData) {
    if (!matchData.matched()) {
      return string;
    }
    Matcher matcher = CAPTURE_GROUP_REGEX.matcher(string);
    StringBuilder result = new StringBuilder();
    int lastPosition = 0;
    while (matcher.find()) {
      int groupIndex = StringUtilRt.parseInt(matcher.group(1) != null ? matcher.group(1) : matcher.group(2), -1);
      if (groupIndex >= 0 && matchData.count() > groupIndex) {
        result.append(string, lastPosition, matcher.start());
        TextMateRange range = matchData.byteOffset(groupIndex);
        String capturedText = new String(matchingString.bytes, range.start, range.getLength(), StandardCharsets.UTF_8);
        int numberOfDotsAtTheBeginning = Strings.countChars(capturedText, '.', 0, true);
        String replacement = capturedText.substring(numberOfDotsAtTheBeginning);
        String command = matcher.group(3);
        if ("downcase".equals(command)) {
          result.append(replacement.toLowerCase(Locale.ROOT));
        }
        else if ("upcase".equals(command)) {
          result.append(replacement.toUpperCase(Locale.ROOT));
        }
        else {
          result.append(replacement);
        }
        lastPosition = matcher.end();
      }
    }
    if (lastPosition < string.length()) {
      result.append(string.subSequence(lastPosition, string.length()));
    }
    return result.toString();
  }
public static CharSequence replaceGroupsWithMatchDataInCaptures(@NotNull CharSequence string,
                                                                  @NotNull StringWithId matchingString,
                                                                  @NotNull MatchData matchData)