@Contract(pure = true)
  @ApiStatus.Internal
  public static int naturalCompare(@NotNull String s1,
                                   @NotNull String s2,
                                   int length1,
                                   int length2,
                                   boolean ignoreCase,
                                   boolean likeFileNames) {
    int i = 0;
    int j = 0;
    for (; i < length1 && j < length2; i++, j++) {
      final char ch1 = s1.charAt(i);
      final char ch2 = s2.charAt(j);
      if ((Strings.isDecimalDigit(ch1) || ch1 == ' ') && (Strings.isDecimalDigit(ch2) || ch2 == ' ')) {
        final int start1 = skipChar(s1, skipChar(s1, i, length1, ' '), length1, '0');
        final int start2 = skipChar(s2, skipChar(s2, j, length2, ' '), length2, '0');

        final int end1 = skipDigits(s1, start1, length1);
        final int end2 = skipDigits(s2, start2, length2);

        // numbers with more digits are always greater than shorter numbers
        final int lengthDiff = (end1 - start1) - (end2 - start2);
        if (lengthDiff != 0) return lengthDiff;

        // compare numbers with equal digit count
        final int numberDiff = compareCharRange(s1, s2, start1, start2, end1);
        if (numberDiff != 0) return numberDiff;

        // compare number length including leading spaces and zeroes
        final int fullLengthDiff = (end1 - i) - (end2 - j);
        if (fullLengthDiff != 0) return fullLengthDiff;

        // the numbers are the same; compare leading spaces and zeroes
        final int leadingDiff = compareCharRange(s1, s2, i, j, start1);
        if (leadingDiff != 0) return leadingDiff;

        i = end1 - 1;
        j = end2 - 1;
      }
      else if (likeFileNames) {
        //for super natural comparison (IDEA-80435)
        if (ch1 != ch2) {
          final int diff;
          if (ch1 == '-' && ch2 != '_') {
            diff = compareChars('_', ch2, ignoreCase);
          }
          else if (ch2 == '-' && ch1 != '_') {
            diff = compareChars(ch1, '_', ignoreCase);
          }
          else {
            diff = compareChars(ch1, ch2, ignoreCase);
          }
          if (diff != 0) return diff;
        }
      }
      else {
        final int diff = compareChars(ch1, ch2, ignoreCase);
        if (diff != 0) return diff;
      }
    }
    // After the loop, the end of one of the strings might not have been reached if the other
    // string ends with a number and the strings are equal until the end of that number.
    // When there are more characters in the string, then it is greater.
    if (i < length1) return +1;
    if (j < length2) return -1;
    if (length1 != length2) return length1 - length2;

    // do case-sensitive compare if case-insensitive strings are equal
    return ignoreCase ? naturalCompare(s1, s2, length1, length2, false, likeFileNames) : 0;
  }
@Contract(pure = true)
  @ApiStatus.Internal
  public static int naturalCompare(@NotNull String s1,
                                   @NotNull String s2,
                                   int length1,
                                   int length2,
                                   boolean ignoreCase,
                                   boolean likeFileNames)