Przytnij ciąg na podstawie jego długości


Odpowiedzi:


272
s = s.substring(0, Math.min(s.length(), 10));

Użycie w Math.minten sposób pozwala uniknąć wyjątku w przypadku, gdy ciąg jest już krótszy niż 10.


Uwagi:

  1. Powyższe robi prawdziwe przycinanie. Jeśli faktycznie chcesz zastąpić ostatnie trzy (!) Znaki kropkami, jeśli jest obcięty, użyj Apache Commons StringUtils.abbreviate.

  2. Może to zachowywać się niepoprawnie 1, jeśli ciąg znaków zawiera punkty kodowe Unicode poza BMP; np. emotikony. Aby uzyskać (bardziej skomplikowane) rozwiązanie, które działa poprawnie dla wszystkich punktów kodowych Unicode, zobacz rozwiązanie @ sibnick .


1 - Punkt kodowy Unicode, który nie znajduje się na płaszczyźnie 0 (BMP) jest reprezentowany jako „para zastępcza” (tj. Dwie charwartości) w pliku String. Ignorując to, możemy przyciąć do mniej niż 10 punktów kodowych lub (co gorsza) obciąć w środku pary zastępczej. Z drugiej strony, String.length()nie jest już idealną miarą długości tekstu Unicode, więc przycinanie na jego podstawie może być niewłaściwą rzeczą.


Czy zamiast Math.min nie możemy przeprowadzić sprawdzenia warunkowego i wykonać podłańcuch tylko wtedy, gdy łańcuch ma wartość max? np .:s = (s.length() > 10) ? s.substring(0,10) : s ;
rram

1
Tak oczywiście możesz. Przeczytaj inne odpowiedzi, aby poznać inne sposoby rozwiązania problemu!
Stephen C

137

StringUtils.abbreviatez biblioteki Apache Commons Lang może być Twoim przyjacielem:

StringUtils.abbreviate("abcdefg", 6) = "abc..."
StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
StringUtils.abbreviate("abcdefg", 4) = "a..."

Commons Lang3 pozwala nawet ustawić niestandardowy ciąg jako znacznik zastępczy. W ten sposób możesz na przykład ustawić pojedynczy znak wielokropka.

StringUtils.abbreviate("abcdefg", "\u2026", 6) = "abcde…"

5
Mógłby być, ale w pytaniu PO nie chodzi o „wielokropek”.
Stephen C

9
@StephenC - Pytanie zawiera 8 znaków, po których następują 2 kropki, biorąc pod uwagę limit długości 10, co jest bardzo podobne do wielokropka (tylko 2 kropki zamiast 3). Jest również prawdopodobne, że wiele osób, które znajdą to pytanie, uznałoby wielokropek za przydatny.
ToolmakerSteve

12
... a jeśli nie chcesz elipsy, może ci pomóc StringUtils.left ().
Superole

1
FYI, HORIZONTAL ELLIPSIS to pojedynczy znak, a nie trzy znaki FULL STOP :…
Basil Bourque

58

Jest to StringUtilsfunkcja Apache Commons, która to robi.

s = StringUtils.left(s, 10)

Jeśli len znaków nie jest dostępnych lub String ma wartość null, String zostanie zwrócony bez wyjątku. Jeśli len jest ujemne, zwracany jest pusty ciąg.

StringUtils.left (null, ) = null
StringUtils.left (
, -ve) = ""
StringUtils.left ("", *) = ""
StringUtils.left ("abc", 0) = ""
StringUtils.left (" abc ", 2) =" ab "
StringUtils.left (" abc ", 4) =" abc "

StringUtils.Left JavaDocs

Dzięki uprzejmości: Steeve McCauley


22

Jak zwykle nikogo nie obchodzą zastępcze pary UTF-16. Zobacz o nich: Jakie są najczęściej używane znaki Unicode inne niż BMP? Nawet autorzy org.apache.commons / commons-lang3

Możesz zobaczyć różnicę między poprawnym kodem a zwykłym kodem w tym przykładzie:

public static void main(String[] args) {
    //string with FACE WITH TEARS OF JOY symbol
    String s = "abcdafghi\uD83D\uDE02cdefg";
    int maxWidth = 10;
    System.out.println(s);
    //do not care about UTF-16 surrogate pairs
    System.out.println(s.substring(0, Math.min(s.length(), maxWidth)));
    //correctly process UTF-16 surrogate pairs
    if(s.length()>maxWidth){
        int correctedMaxWidth = (Character.isLowSurrogate(s.charAt(maxWidth)))&&maxWidth>0 ? maxWidth-1 : maxWidth;
        System.out.println(s.substring(0, Math.min(s.length(), correctedMaxWidth)));
    }
}

1
Znalazłem błąd w jira Apache commons: Issues.apache.org/jira/browse/LANG-1343
Ryan Quinn

10

s = s.length() > 10 ? s.substring(0, 9) : s;


16
Drugi parametr podciągu jest wyłączny, więc ta odpowiedź skraca ciąg do 9 znaków.
emulcahy

9

Lub możesz po prostu użyć tej metody na wypadek, gdybyś nie miał pod ręką StringUtils:

public static String abbreviateString(String input, int maxLength) {
    if (input.length() <= maxLength) 
        return input;
    else 
        return input.substring(0, maxLength-2) + "..";
}

Twój kod nie działa dla mnie. Spróbuj tegoSystem.out.println(abbreviateString("ABC\ud83d\udc3bDEF", 6));
T3rm1

4

Na wypadek gdybyś szukał sposobu na przycięcie i zachowanie OSTATNICH 10 znaków ciągu.

s = s.substring(Math.max(s.length(),10) - 10);

3

Z Kotlin jest to tak proste, jak:

yourString.take(10)

Zwraca ciąg zawierający pierwsze n znaków z tego ciągu lub cały ciąg, jeśli ten ciąg jest krótszy.

Dokumentacja


2

tl; dr

Wydaje się, że podczas obcinania pytasz o znak wielokropka ( ) na ostatnim miejscu. Oto jednowierszowy sposób manipulowania ciągiem wejściowym.

String input = "abcdefghijkl";
String output = ( input.length () > 10 ) ? input.substring ( 0 , 10 - 1 ).concat ( "…" ) : input;

Zobacz, jak działa ten kod na IdeOne.com.

abcdefghi…

Operator trójskładnikowy

Możemy utworzyć jedną linijkę, używając operatora trójskładnikowego .

String input = "abcdefghijkl" ;

String output = 
    ( input.length() > 10 )          // If too long…
    ?                                
    input     
    .substring( 0 , 10 - 1 )         // Take just the first part, adjusting by 1 to replace that last character with an ellipsis.
    .concat( "…" )                   // Add the ellipsis character.
    :                                // Or, if not too long…
    input                            // Just return original string.
;

Zobacz, jak działa ten kod na IdeOne.com.

abcdefghi…

Strumienie Java

Funkcja Java Streams sprawia, że ​​jest to interesujące, od wersji Java 9 i nowszych. Ciekawe, ale może nie najlepsze podejście.

Używamy raczej punktów kodowych niż charwartości. charTyp jest dziedzictwo i jest ograniczona do podzbioru wszystkich możliwych Unicode znaków.

String input = "abcdefghijkl" ;
int limit = 10 ;
String output =
        input
                .codePoints()
                .limit( limit )
                .collect(                                    // Collect the results of processing each code point.
                        StringBuilder::new,                  // Supplier<R> supplier
                        StringBuilder::appendCodePoint,      // ObjIntConsumer<R> accumulator
                        StringBuilder::append                // BiConsumer<R,​R> combiner
                )
                .toString()
        ;

Jeśli obcięto nadmiar znaków, zamień ostatni znak na wielokropek .

if ( input.length () > limit )
{
    output = output.substring ( 0 , output.length () - 1 ) + "…";
}

Gdybym tylko mógł wymyślić sposób na połączenie linii strumienia z częścią „jeśli przekroczysz limit, wykonaj wielokropek”.


Nie. Najwyraźniej chce skrócić sznurek, jeśli osiągnie długość 11 lub więcej. Musisz pracować nad nowym systemem AI oO
JD333

1
@ JD333 Twój komentarz wymyka mi się. Obcięcie do długości 10 łącznie z wielokropkiem jest dokładnie tym, co tutaj pokazuję.
Basil Bourque

0
str==null ? str : str.substring(0, Math.min(str.length(), 10))

lub,

str==null ? "" : str.substring(0, Math.min(str.length(), 10))

Działa z null.


0

Oto rozwiązanie Kotlin

Jedna linia,

if (yourString?.length!! >= 10) yourString?.take(90).plus("...") else yourString

Tradycyjny,

if (yourString?.length!! >= 10) {
  yourString?.take(10).plus("...")
 } else {
  yourString
 }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.