Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to abbreviate string at the middle without cutting words

Tags:

java

string

I am using StringUtils.abbreviateMiddle(string, middle, targetLength); to abbreviate string in the middle but using this method cuts off the word. Is there a way such that it will only cut off string at the space nearest to the middle position of the string?

public static String shortenStringMiddle(String string, String middle, int targetLength) {
    targetLength = Math.abs(targetLength);

    if (string != null && string.length() > targetLength) {

        return StringUtils.abbreviateMiddle(string, middle, targetLength);
    }
    else {
        return string;
    }
}

Input if applied to this text:

Disease Control in Fish and Shrimp Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques: Proceedings of the SEAFDEC-OIE Seminar-Workshop on Disease Control in Fish and Shrimp Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques, 4-6 December 2001, Iloilo City, Philippines

System.out.println(StringUtils.abbreviateMiddle("Disease Control in Fish and Shrimp Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques: Proceedings of the SEAFDEC-OIE Seminar-Workshop on Disease Control in Fish and Shrimp Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques, 4-6 December 2001, Iloilo City, Philippines", " … ", 220));

Output:

Disease Control in Fish and Shrimp Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques: Proceeaculture in Southeast Asia - Diagnosis and Husbandry Techniques, 4-6 December 2001, Iloilo City, Philippines

The word Proceedings was cut off to Procee and Aquaculture to aculture

My ideal output would be:

Disease Control in Fish and Shrimp Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques: Proceedings … Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques, 4-6 December 2001, Iloilo City, Philippines

I've searched here in SO and similar questions only relates to abbreviate string adding an ellipsis at the end.

like image 229
euler Avatar asked Aug 07 '15 01:08

euler


2 Answers

Here's a rough shot at it. Obviously you could implement cleaner fallback methods for cases where the string doesn't contain sufficient spaces etc., but as a base to start from, it should do just fine.

public static String abbreviateMiddle(String input, String middle, int targetLength) {
    if (input == null || input.length() <= targetLength) {
        return input;
    }

    int inputLength = input.length();
    int halfTargetLength = (targetLength - middle.length()) / 2;

    int startLastSpace = input.substring(0, halfTargetLength).lastIndexOf(" ");
    int endFirstSpace = input.indexOf(" ", inputLength - halfTargetLength);

    if (startLastSpace != -1 || endFirstSpace != -1) {
        return input.substring(0, startLastSpace)
                + middle
                + input.substring(endFirstSpace + 1, inputLength);
    }

    return input;
}

With your example text, the following call

System.out.println(abbreviateMiddle(exampleText, " ... ", 240));

will return

Disease Control in Fish and Shrimp Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques: Proceedings ... Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques, 4-6 December 2001, Iloilo City, Philippines

Setting the targetLength to 220 will return

Disease Control in Fish and Shrimp Aquaculture in Southeast Asia - Diagnosis and Husbandry Techniques: ... in Southeast Asia - Diagnosis and Husbandry Techniques, 4-6 December 2001, Iloilo City, Philippines

like image 178
Robby Cornelissen Avatar answered Nov 06 '22 14:11

Robby Cornelissen


Try this:

public String abbreviateMiddle(String string, String middle, int targetLength) {
    String[] ssplit = string.split(" ");
    String first = "";
    String second = "";
    for (int i = 0; i < ssplit.length; i++) {
        if (first.length() < targetLength / 2) {
            first += ssplit[i] + " ";
        } else {
            break;
        }
    }
    for (int i = ssplit.length - 1; i >= 0; i--) {
        if (second.length() < targetLength / 2) {
            second = ssplit[i] + " " + second;
        } else {
            break;
        }
    }

    return first + middle + second;
}

If you want the result string to be maximum length but strictly less than targetLength (rather than the above code which returns the minimum string that has a length GREATER than targetLength), use

if (first.length() + ssplit[i].length() < targetLength /2)

and

if (second.length() + ssplit[i].length() < targetLength / 2)

instead.

like image 38
M. Shaw Avatar answered Nov 06 '22 14:11

M. Shaw