Come posso ottenere i primi n caratteri di una stringa senza controllare la dimensione o andare fuori dai limiti?


163

Come faccio ad arrivare ai primi ncaratteri di una stringa in Java senza prima fare un controllo dimensionale (inline è accettabile) o rischiare un IndexOutOfBoundsException?


1
a meno che tu non capisca l'eccezione, non so come pensi di gestire il caso in cui la lunghezza del carattere è maggiore della lunghezza della stringa.
Matt Boehm,

2
Perché? Qual è la tua avversione per il controllo della lunghezza o la cattura di un'eccezione?
paxdiablo,

1
A causa della curiosità, perché vuoi evitare il controllo delle dimensioni. Questo non è C.
Tom Hawtin - tackline

ciò che intendevo esprimere era il desiderio di evitare un blocco if / else, non un'avversione al controllo della lunghezza.
antony.trupe,

Risposte:


347

Ecco una soluzione pulita:

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

Opinione: sebbene questa soluzione sia "pulita", penso che in realtà sia meno leggibile di una soluzione che usa if/ elsenel modo ovvio. Se il lettore non ha visto questo trucco, deve pensare di più per capire il codice. IMO, il significato del codice è più evidente nella versione if/ else. Per una soluzione più pulita / più leggibile, vedere la risposta di @ paxdiablo.


1
+1. Ancora meglio se questo è racchiuso in una funzione chiamata safe_substring o substring_safe, come la risposta di paxdiablo, in modo che l'uso sia più facile da leggere / intento più ovvio.
ToolmakerSteve

Non sono d'accordo con quello che stai dicendo. Se questo è racchiuso in una funzione, non importa cosa c'è dentro la funzione , e ogni "pulizia" è decisamente compensata dalla mancanza di chiarezza. Il punto di questa soluzione è che è "pulito" nel caso in cui non si desideri creare una funzione wrapper.
Stephen C,

88

Non reinventare la ruota ...:

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

Javadoc dice:

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"

Così:

StringUtils.substring("abc", 0, 4) = "abc"

1
Non risponde alla domanda, ma a prescindere fornisce comunque la soluzione. Se l'OP è in grado di capire, penso che questa sia una soluzione migliore.
aullah

5
Potrebbe anche essere utile sottolineare che StringUtils.substring(yourString, 0, n)non è lo stesso di yourString.substring(0, n). Il primo proviene da StringUtils, mentre il secondo sta usando String.substring(il che dà un'eccezione se l'indice finale supera la lunghezza della stringa).
ToolmakerSteve

Proprio come FYI se cerchi nella fonte questo metodo, sta gestendo il caso in cui la fine è maggiore della lunghezza cambiando la fine in lunghezza:if (end > str.length()) { end = str.length();}
bholl

1
L'ultimo parametro di StringUtils.substring(String s, int start, int len)non è len, è l'indice di fine.
gorootde,

StringUtils.substring ("abc", 0, 4) = "abc", ha funzionato per me. Grazie !
Akash5288,

42

Apache Commons Lang ha un StringUtils.leftmetodo per questo.

String upToNCharacters = StringUtils.left(s, n);

Non dovrebbe essere questa la soluzione migliore? Perché molti non lo votano?
Do Will,

3
Forse perché altre persone non hanno la tua stessa opinione? :-)
Stephen C

questa risposta è arrivata molto più tardi rispetto alla data della domanda originale.
Mulki,

@DoWill: perché l'aggiunta di una (altra) libreria di terze parti al tuo ambiente eseguibile non è sempre utile.
LarsH,

12

C'è una classe di domande su SO che a volte hanno meno di un senso perfetto, questa è pericolosamente vicina :-)

Forse potresti spiegare la tua avversione all'uso di uno dei due metodi che hai escluso.

Se è solo perché non vuoi aggiungere il tuo codice con ifistruzioni o codice di rilevazione delle eccezioni, una soluzione è quella di utilizzare una funzione di supporto che se ne occuperà per te, qualcosa come:

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

che controllerà in anticipo le lunghezze e agirà di conseguenza (o restituisce una stringa più piccola o un pad con spazi).

Quindi non devi preoccuparti di questo nel tuo codice, basta chiamare:

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

invece di:

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

Ciò funzionerebbe nel caso in cui sembri preoccupato (in base ai tuoi commenti ad altre risposte), non interrompere il flusso del codice quando si eseguono molte operazioni di creazione di stringhe.


1
Dovresti leggere il commento più da vicino, @antony, in particolare lo smiley, e non essere così prezioso su coloro che cercano di aiutare. Stavo semplicemente affermando che non avevi dato alcuna logica al perché dovevi evitare i due metodi. E questa è una risposta autentica, usando una funzione di aiuto, motivo per cui non è in un commento.
paxdiablo,

1
+1: Questo è un approccio MOLTO migliore di quello accettato, dato il desiderio di OP di non ingombrare il codice. (o vedi la soluzione di Nickkk di includere una libreria che ha già una funzione che si comporti come desiderato.)
ToolmakerSteve

12
String upToNCharacters = String.format("%."+ n +"s", str);

Pessimo se nè una variabile (quindi è necessario costruire la stringa di formato), ma abbastanza chiaro se una costante:

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

docs


Alternativa interessante, anche se non riesco a immaginare di usarla mai, visti gli approcci più tradizionali, che sono stati dati quattro anni fa.
ToolmakerSteve

La migliore risposta perché l'input String viene letto solo una volta, quindi non è necessario memorizzarlo in una variabile, il che rende possibile incorporarlo in modo ordinato.
Profiterole,

3

Utilizzare il metodo di sottostringa, come segue:

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

Se n è maggiore della lunghezza della stringa, ciò genererà un'eccezione, come ha sottolineato un commentatore. una soluzione semplice è quella di avvolgere tutto questo nella condizione if(s.length()<n)nella elseclausola, puoi scegliere se vuoi solo stampare / restituire l'intera stringa o gestirla in un altro modo.


1
questo rischia di ottenere un IndexOutOfBoundsException
antony.trupe,

A proposito, se hai intenzione di programmare in Java, dovresti provare a memorizzare la maggior parte dei metodi API per String ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
Matt Boehm,

Ho già escluso la sottostringa, almeno da sola, come non la risposta.
antony.trupe,

Devi controllare le dimensioni o prendere l'eccezione. Posso chiederti perché fare una di queste due cose non funzionerebbe nella tua situazione?
Matt Boehm,

3
In che modo questa è una risposta alla domanda? La domanda era: come NON effettuare prima un controllo dimensionale, né causare un'eccezione che deve essere colta.
ToolmakerSteve

3

Se sei abbastanza fortunato da sviluppare con Kotlin,
puoi usarlo takeper raggiungere il tuo obiettivo.

val someString = "hello"

someString.take(10) // result is "hello"
someString.take(4) // result is "hell" )))

0

ApacheCommons mi ha sorpreso, StringUtils.abbreviate(String str, int maxWidth)aggiunge "..." non c'è alcuna opzione per cambiare postfix. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)guarda al prossimo spazio vuoto.

Lo lascerò qui:

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

1
@ VolkanGüven È a causa di questa frase "ApacheCommons mi ha sorpreso". Ho commesso peccato attraverso la critica della sacra biblioteca di ApacheCommons. O comunque ...
Yuceel,

0

Kotlin: (Se qualcuno ha bisogno)

var mText = text.substring(0, text.length.coerceAtMost(20))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.