@Override
  public void split(@Nullable String text, @NotNull TextRange range, Consumer<TextRange> consumer) {
    if (StringUtil.isEmpty(text)) {
      return;
    }
    final Splitter ws = getTextSplitter();
    int from = range.getStartOffset();
    int till;

    try {
      Matcher matcher;
      final String substring = range.substring(text).replace('\b', '\n').replace('\f', '\n');
      if (Verifier.checkCharacterData(SPLIT_PATTERN.matcher(newBombedCharSequence(substring)).replaceAll("")) != null) {
        return;
      }
      matcher = SPLIT_PATTERN.matcher(newBombedCharSequence(text, range));

      while (true) {
        checkCancelled();

        List<TextRange> toCheck;
        TextRange wRange;
        String word;

        if (matcher.find()) {
          TextRange found = matcherRange(range, matcher);
          till = found.getStartOffset();
          if (badSize(from, till)) {
            from = found.getEndOffset();
            continue;
          }
          wRange = new TextRange(from, till);
          word = wRange.substring(text);
          from = found.getEndOffset();
        }
        else { // end hit or zero matches
          wRange = new TextRange(from, range.getEndOffset());
          word = wRange.substring(text);
        }

        int wordLength = word.length();

        if (word.contains("@")) {
          toCheck = excludeByPattern(text, wRange, MAIL, 0);
        }
        else if (word.contains("://")) {
          toCheck = excludeByPattern(text, wRange, URL_PATTERN, 0);
        }
        else if (word.startsWith(JWT_COMMON_PREFIX) && JWT_PATTERN.matcher(word).matches()) {
          toCheck = emptyList();
        }
        else if (wordLength == MD5_HEX_LENGTH && MD5_HEX_PATTERN.matcher(word).matches() ||
                 wordLength == SHA1_HEX_LENGTH && SHA1_HEX_PATTERN.matcher(word).matches() ||
                 wordLength == SHA256_HEX_LENGTH && SHA256_HEX_PATTERN.matcher(word).matches() ||
                 wordLength == SHA512_HEX_LENGTH && SHA512_HEX_PATTERN.matcher(word).matches()) {
          toCheck = emptyList();
        }
        else if (wordLength == UUID_V4_HEX_STRING_LENGTH && UUID_PATTERN.matcher(word).matches()) {
          toCheck = emptyList();
        }
        else if (isHashPrefixed(word, SHA384_PREFIX, SHA384_BASE64_LENGTH) && SHA384_PREFIXED_VALUE_PATTERN.matcher(word).matches()
                 || isHashPrefixed(word, SHA512_PREFIX, SHA512_BASE64_LENGTH) && SHA512_PREFIXED_VALUE_PATTERN.matcher(word).matches()) {
          toCheck = emptyList(); // various integrity
        }
        else {
          toCheck = singletonList(wRange);
        }

        for (TextRange r : toCheck) {
          ws.split(text, r, consumer);
        }

        if (matcher.hitEnd()) break;
      }
    }
    catch (ProcessCanceledException ignored) {
    }
  }
@Override
  public void split(@Nullable String text, @NotNull TextRange range, Consumer<TextRange> consumer)