Aparar uma sequência com base no comprimento da sequência

136

Quero cortar uma string se o comprimento exceder 10 caracteres.

Suponha que, se o comprimento da string for 12 ( String s="abcdafghijkl"), a nova string aparada contenha "abcdefgh..".

Como posso conseguir isso?

yshak
fonte
6
possível duplicata de até os primeiros N caracteres
Stephen C
FYI, uma HORIZONTAL ELLIPSIS é um único caractere, não dois ou três Full Stop personagens: ...
Basil Bourque

Respostas:

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

Usar Math.mindesta forma evita uma exceção no caso em que a string já é menor que 10.


Notas:

  1. O exemplo acima faz um corte real. Se você realmente deseja substituir os três últimos caracteres (!) Por pontos, se truncar, use o Apache Commons StringUtils.abbreviate.

  2. Isso pode se comportar incorretamente 1 se sua String contiver pontos de código Unicode fora do BMP; por exemplo, Emojis. Para uma solução (mais complicada) que funciona corretamente para todos os pontos de código Unicode, consulte a solução da @ sibnick .


1 - Um ponto de código Unicode que não está no plano 0 (o BMP) é representado como um "par substituto" (ou seja, dois charvalores) no String. Ao ignorar isso, podemos reduzir para menos de 10 pontos de código ou (pior) truncar no meio de um par substituto. Por outro lado, String.length()não é mais uma medida ideal do tamanho do texto Unicode, portanto, aparar com base nela pode ser a coisa errada a fazer.

Stephen C
fonte
Em vez de Math.min, não podemos fazer uma verificação condicional e fazer substring apenas se a string for max, em seguida, necessária? por exemplo:s = (s.length() > 10) ? s.substring(0,10) : s ;
rram 14/02/19
1
Sim, é claro que você pode. Leia as outras respostas para outras maneiras de resolver o problema!
Stephen C
132

StringUtils.abbreviateda biblioteca Apache Commons Lang poderia ser seu amigo:

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

O Commons Lang3 ainda permite definir uma String personalizada como marcador de substituição. Com isso, você pode, por exemplo, definir reticências de um único caractere.

StringUtils.abbreviate("abcdefg", "\u2026", 6) = "abcde…"
H6
fonte
5
Poderia ser, mas a pergunta do OP não pede "reticências".
Stephen C
9
@StephenC - A pergunta mostra 8 caracteres seguidos por 2 pontos, dado um limite de comprimento de 10, que é muito parecido com uma elipse (apenas 2 pontos em vez de 3). Também é provável que muitas das pessoas que acham essa pergunta considerem uma elipse útil.
Página Inicial>
12
... e se você não deseja as reticências, o StringUtils.left () pode ajudá-lo.
Superole 15/10
1
FYI, uma HORIZONTAL ELLIPSIS é um único caractere, e não três Ponto Final personagens: ...
Basil Bourque
53

Existe uma StringUtilsfunção Apache Commons que faz isso.

s = StringUtils.left(s, 10)

Se os caracteres len não estiverem disponíveis ou a String for nula, a String será retornada sem uma exceção. Uma String vazia será retornada se len for negativo.

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

Cortesia: Steeve McCauley

Mulki
fonte
22

Como sempre, ninguém se importa com pares substitutos UTF-16. Veja sobre eles: Quais são os caracteres Unicode não BMP mais comuns em uso real? Até autores de org.apache.commons / commons-lang3

Você pode ver a diferença entre o código correto e o código usual neste exemplo:

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)));
    }
}
sibnick
fonte
1
Encontrei o bug no jira do Apache commons: issues.apache.org/jira/browse/LANG-1343
Ryan Quinn
10

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

shift66
fonte
16
O segundo parâmetro de substring é exclusivo, portanto, essa resposta corta a String em 9 caracteres.
Emulcahy
8

Ou você pode simplesmente usar esse método caso não tenha o StringUtils disponível:

public static String abbreviateString(String input, int maxLength) {
    if (input.length() <= maxLength) 
        return input;
    else 
        return input.substring(0, maxLength-2) + "..";
}
MVojtkovszky
fonte
Seu código não funcionou para mim. Tente issoSystem.out.println(abbreviateString("ABC\ud83d\udc3bDEF", 6));
T3rm1 28/07
4

Caso você esteja procurando uma maneira de aparar e manter os ÚLTIMOS 10 caracteres de uma string.

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

Com o Kotlin, é tão simples quanto:

yourString.take(10)

Retorna uma sequência que contém os primeiros n caracteres dessa sequência ou a sequência inteira, se essa sequência for menor.

Documentação

Leo Droidcoder
fonte
1

tl; dr

Você parece estar solicitando um caractere de reticências ( ) em último lugar, ao truncar. Aqui está uma linha para manipular sua sequência de entrada.

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

Veja este código executado ao vivo em IdeOne.com.

abcdefghi…

Operador ternário

Podemos criar uma linha usando o operador ternário .

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.
;

Veja este código executado ao vivo em IdeOne.com.

abcdefghi…

Fluxos Java

O recurso Java Streams torna isso interessante, a partir do Java 9 e posterior. Interessante, mas talvez não seja a melhor abordagem.

Usamos pontos de código em vez de charvalores. O chartipo é herdado e está limitado ao subconjunto de todos os caracteres Unicode possíveis .

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()
        ;

Se houver caracteres em excesso truncados, substitua o último caractere por uma elipse .

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

Se ao menos eu conseguisse pensar em uma maneira de montar a linha do fluxo com a parte "se estiver acima do limite, faça reticências".

Basil Bourque
fonte
Não. Claramente, ele deseja cortar o comprimento da corda se ela atingir um comprimento de 11 ou mais. Você deve estar trabalhando em um novo sistema AI oO
JD333 2/19/19
1
@ JD333 Seu comentário me escapa. Truncar até 10, incluindo as reticências, é exatamente o que mostro aqui.
Basil Bourque
0
str==null ? str : str.substring(0, Math.min(str.length(), 10))

ou,

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

Funciona com nulo.

aceminds
fonte