Como obtenho os primeiros n caracteres de uma sequência sem verificar o tamanho ou sair dos limites?

163

Como faço para obter os primeiros ncaracteres de uma string em Java sem fazer uma verificação de tamanho primeiro (a linha é aceitável) ou arriscar IndexOutOfBoundsException?

antony.trupe
fonte
1
a menos que você capture a exceção, não sei como planeja lidar com o caso em que o comprimento do caractere é maior que o comprimento da String.
22810 Matt Boehm
2
Por quê? Qual é a sua aversão em verificar o comprimento ou capturar uma exceção?
21420
1
Por curiosidade, por que você deseja evitar a verificação do tamanho. Este não é C.
Tom Hawtin - tackline
o que eu pretendia expressar era um desejo de evitar um bloco if / else, não uma aversão a realmente verificar o comprimento.
antony.trupe
potencial duplicado de: stackoverflow.com/questions/8499698/…
Mulki 12/02/19

Respostas:

347

Aqui está uma solução elegante:

String upToNCharacters = s.substring(0, Math.min(s.length(), n));

Opinião: embora essa solução seja "pura", acho que é realmente menos legível do que uma solução que usa if/ elseda maneira óbvia. Se o leitor não viu esse truque, ele / ela precisa pensar mais para entender o código. IMO, o significado do código é mais óbvio na versão if/ else. Para uma solução mais limpa / legível, consulte a resposta de @ paxdiablo.

Stephen C
fonte
1
+1. Melhor ainda se isso estiver envolvido em uma função chamada safe_substring ou substring_safe, como a resposta de paxdiablo, para que o uso seja mais fácil de ler / intenção, mais óbvio.
Página Inicial>
Não concordo com o que você está dizendo. Se isso estiver envolvido em uma função, não importa o que está dentro da função e qualquer "limpeza" é definitivamente superada pela falta de clareza. O ponto desta solução é que ela é "pura" para o caso em que você não deseja criar uma função de wrapper.
Stephen C
88

Não reinvente a roda ...:

org.apache.commons.lang.StringUtils.substring(String s, int start, int len)

Javadoc diz:

StringUtils.substring(null, *, *)    = null
StringUtils.substring("", * ,  *)    = "";
StringUtils.substring("abc", 0, 2)   = "ab"
StringUtils.substring("abc", 2, 0)   = ""
StringUtils.substring("abc", 2, 4)   = "c"
StringUtils.substring("abc", 4, 6)   = ""
StringUtils.substring("abc", 2, 2)   = ""
StringUtils.substring("abc", -2, -1) = "b"
StringUtils.substring("abc", -4, 2)  = "ab"

Portanto:

StringUtils.substring("abc", 0, 4) = "abc"
Nickkk
fonte
1
Não responde à pergunta, mas, independentemente disso, ainda fornece a solução. Se o OP é capaz de entender, acho que essa é uma solução melhor.
aullah
5
Também pode ser útil ressaltar que StringUtils.substring(yourString, 0, n)não é o mesmo que yourString.substring(0, n). O primeiro é de StringUtils, enquanto o último está usando String.substring(o que dá exceção se o índice final exceder o comprimento da string).
Página Inicial>
Assim como FYI, se você olhar na fonte para este método sua manipulação do caso em que o final é maior que o comprimento alterando o fim ao comprimento:if (end > str.length()) { end = str.length();}
bholl
1
O último parâmetro de StringUtils.substring(String s, int start, int len)não é len, é o índice final.
precisa saber é o seguinte
StringUtils.substring ("abc", 0, 4) = "abc", funcionou para mim. Obrigado !
precisa saber é o seguinte
42

O Apache Commons Lang tem um StringUtils.leftmétodo para isso.

String upToNCharacters = StringUtils.left(s, n);
Skuli
fonte
Essa não deveria ser a melhor solução? Por que muitos não votam nisso?
você
3
Talvez porque outras pessoas não tenham a mesma opinião que você? :-)
Stephen C
essa resposta chegou muito depois da data original da pergunta.
Mulki
@ DoWill: porque nem sempre vale a pena adicionar uma (outra) biblioteca de terceiros ao seu ambiente executável.
Larsh
12

Há uma classe de perguntas sobre SO que às vezes fazem menos do que perfeito sentido; esta é perigosamente próxima :-)

Talvez você possa explicar sua aversão ao uso de um dos dois métodos que descartou.

Se é apenas porque você não deseja incluir seu código em ifinstruções ou códigos de captura de exceção, uma solução é usar uma função auxiliar que cuidará disso para você, algo como:

static String substring_safe (String s, int start, int len) { ... }

que verificará os comprimentos antecipadamente e agirá de acordo (retorne uma string menor ou use um espaço com espaços).

Então você não precisa se preocupar com isso no seu código, basta ligar para:

String s2 = substring_safe (s, 10, 7);

ao invés de:

String s2 = s.substring (10,7);

Isso funcionaria no caso em que você pareça estar preocupado (com base nos seus comentários para outras respostas), em não interromper o fluxo do código ao fazer várias coisas de construção de strings.

paxdiablo
fonte
1
Você deve ler o comentário mais de perto, @antony, especialmente o smiley, e não ser tão precioso sobre quem está tentando ajudar. Eu estava apenas afirmando que você não havia fundamentado o motivo pelo qual tinha que evitar os dois métodos. E esta é uma resposta genuína, usando uma função auxiliar, e é por isso que não está em um comentário.
paxdiablo
1
+1: Essa é uma abordagem MUITO melhor que a aceita, dado o desejo do OP de não desorganizar o código. (ou ver solução de incluir uma biblioteca que já tem uma função que se comporta como desejado do Nickkk.)
ToolmakerSteve
12
String upToNCharacters = String.format("%."+ n +"s", str);

Horrível se nfor uma variável (portanto, você deve construir a sequência de formatação), mas bem claro se for uma constante:

String upToNCharacters = String.format("%.10s", str);

docs

13ren
fonte
Alternativa interessante, embora eu não possa imaginar usá-lo, dadas as abordagens mais tradicionais, que foram dadas há quatro anos.
Página Inicial>
Melhor resposta, porque a String de entrada é lida apenas uma vez, portanto não há necessidade de armazená-la em uma variável, o que torna possível incorporá-la perfeitamente.
Profiterole
3

Use o método de substring, da seguinte maneira:

int n = 8;
String s = "Hello, World!";
System.out.println(s.substring(0,n);

Se n for maior que o comprimento da string, isso gerará uma exceção, como apontou um comentarista. Uma solução simples é agrupar tudo isso na condição if(s.length()<n)de sua elsecláusula, você pode escolher se deseja apenas imprimir / retornar a String inteira ou lidar com ela de outra maneira.

Matt Boehm
fonte
1
esta corre o risco de obter uma IndexOutOfBoundsException
antony.trupe
A propósito, se você planeja programar em Java, tente memorizar a maioria dos métodos de API para String ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
22810 Matt Boehm
Eu já descartei a substring, pelo menos por si só, como não a resposta.
68610 antonio.trupe 18/10/09
Você deve verificar o tamanho ou capturar a exceção. Posso perguntar por que fazer isso não funcionaria na sua situação?
22810 Matt Boehm
3
Como isso é uma resposta para a pergunta? A questão era perguntar como NÃO é necessário fazer uma verificação de tamanho primeiro, nem causar uma exceção que precise ser detectada.
Página Inicial>
3

Se você tiver sorte o suficiente para desenvolver com o Kotlin,
poderá usar takepara atingir seu objetivo.

val someString = "hello"

someString.take(10) // result is "hello"
someString.take(4) // result is "hell" )))
Leo Droidcoder
fonte
0

O ApacheCommons me surpreendeu, StringUtils.abbreviate(String str, int maxWidth)acrescenta "...", não há opção para alterar o postfix. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)procura o próximo espaço vazio.

Eu só vou deixar isso aqui:

public static String abbreviate(String s, int maxLength, String appendToEnd) {
    String result = s;
    appendToEnd = appendToEnd == null ? "" : appendToEnd;
    if (maxLength >= appendToEnd.length()) {
        if (s.length()>maxLength) {
            result = s.substring(0, Math.min(s.length(), maxLength - appendToEnd.length())) + appendToEnd;
        }
    } else {
        throw new StringIndexOutOfBoundsException("maxLength can not be smaller than appendToEnd parameter length.");
    }
    return result;
}
yuceel
fonte
1
@ VolkanGüven É por causa dessa frase "ApacheCommons me surpreendeu". Cometi pecado através da crítica da santa biblioteca ApacheCommons. Ou seja o que for ...
yuceel 11/11/19
0

Kotlin: (Se alguém precisar)

var mText = text.substring(0, text.length.coerceAtMost(20))
Touhid
fonte