¿Cómo obtengo los primeros n caracteres de una cadena sin verificar el tamaño o salir de los límites?

163

¿Cómo llego a los primeros ncaracteres de una cadena en Java sin hacer primero una verificación de tamaño (en línea es aceptable) o arriesgar un IndexOutOfBoundsException?

antony.trupe
fuente
1
a menos que detecte la excepción, no sé cómo planea manejar el caso en el que la longitud del carácter es mayor que la longitud de la cadena.
Matt Boehm
2
¿Por qué? ¿Cuál es su aversión a verificar la longitud o detectar una excepción?
paxdiablo
1
Por curiosidad, ¿por qué quieres evitar el control de tamaño? Esto no es C.
Tom Hawtin - tackline
lo que quise expresar fue un deseo de evitar un bloque if / else, no una aversión a verificar la longitud.
antony.trupe
posible duplicado de: stackoverflow.com/questions/8499698/…
Mulki

Respuestas:

347

Aquí hay una solución ordenada:

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

Opinión: si bien esta solución es "ordenada", creo que en realidad es menos legible que una solución que usa if/ elsede la manera obvia. Si el lector no ha visto este truco, tiene que pensar más para entender el código. OMI, el significado del código es más obvio en la versión if/ else. Para una solución más limpia / más legible, vea la respuesta de @ paxdiablo.

Stephen C
fuente
1
+1. Aún mejor si esto está envuelto en una función llamada safe_substring o substring_safe, como la respuesta de paxdiablo, para que el uso sea más fácil de leer / intencionalmente más obvio.
ToolmakerSteve
No estoy de acuerdo con lo que estás diciendo. Si esto está envuelto en una función, no importa lo que esté dentro de la función , y cualquier "pulcritud" definitivamente es superada por la falta de claridad. El punto de esta solución es que es "ordenada" para el caso en el que no desea crear una función de contenedor.
Stephen C
88

No reinventes la rueda ...:

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"

Así:

StringUtils.substring("abc", 0, 4) = "abc"
Nickkk
fuente
1
No responde a la pregunta, pero a pesar de eso, todavía ofrece la solución. Si el OP es capaz de entender, creo que esta es una mejor solución.
aullah
55
También podría ser útil señalar que StringUtils.substring(yourString, 0, n)no es lo mismo que yourString.substring(0, n). El primero es de StringUtils, mientras que el segundo está usando String.substring(lo que da una excepción si el índice final excede la longitud de la cadena).
ToolmakerSteve
Al igual que para su información, si busca en la fuente este método, está manejando el caso donde el final es mayor que la longitud cambiando el final a la longitud:if (end > str.length()) { end = str.length();}
bholl
1
El último parámetro de StringUtils.substring(String s, int start, int len)no es len, es el índice final.
gorootde
StringUtils.substring ("abc", 0, 4) = "abc", funcionó para mí. Gracias !
Akash5288
42

Apache Commons Lang tiene un StringUtils.leftmétodo para esto.

String upToNCharacters = StringUtils.left(s, n);
Skuli
fuente
¿No debería ser esta la mejor solución? ¿Por qué no muchos votan por esto?
Will Will
3
¿Quizás porque otras personas no tienen la misma opinión que tú? :-)
Stephen C
esta respuesta llegó mucho más tarde que la fecha de la pregunta original.
Mulki
@DoWill: Porque agregar una (otra) biblioteca de terceros a su entorno ejecutable no siempre vale la pena.
LarsH
12

Hay una clase de pregunta sobre SO que a veces tiene menos sentido, esta está peligrosamente cerca :-)

Quizás podría explicar su aversión a usar uno de los dos métodos que descartó.

Si es solo porque no quiere sazonar su código con ifdeclaraciones o códigos de captura de excepciones, una solución es usar una función auxiliar que se encargará de usted, algo como:

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

que verificará las longitudes de antemano y actuará en consecuencia (ya sea devolver una cadena más pequeña o rellenar con espacios).

Entonces no tiene que preocuparse por eso en su código, simplemente llame:

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

en vez de:

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

Esto funcionaría en el caso de que parezca estar preocupado (en base a sus comentarios a otras respuestas), no interrumpir el flujo del código al hacer muchas cosas de construcción de cadenas.

paxdiablo
fuente
1
Deberías leer el comentario más de cerca, @antony, especialmente el smiley, y no ser tan valioso sobre aquellos que intentan ayudar. Simplemente estaba afirmando que no habías dado ninguna justificación de por qué tenías que evitar los dos métodos. Y esta es una respuesta genuina, usando una función auxiliar, por lo que no está en un comentario.
paxdiablo
1
+1: Este es un enfoque MUCHO mejor que el aceptado, dado el deseo de OP de no saturar el código. (o ver solución de la inclusión de una biblioteca que ya tiene una función que se comporta como se desea de Nickkk.)
ToolmakerSteve
12
String upToNCharacters = String.format("%."+ n +"s", str);

Horrible si nes una variable (por lo que debe construir la cadena de formato), pero bastante claro si es una constante:

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

docs

13ren
fuente
Alternativa interesante, aunque no puedo imaginar usarlo nunca, dados los enfoques más tradicionales, que se dieron hace cuatro años.
ToolmakerSteve
La mejor respuesta es que la cadena de entrada se lee solo una vez, por lo que no es necesario almacenarla en una variable, lo que permite incrustarla perfectamente.
Profiterole
3

Utilice el método de subcadena, de la siguiente manera:

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

Si n es mayor que la longitud de la cadena, esto generará una excepción, como ha señalado un comentarista. Una solución simple es envolver todo esto en la condición if(s.length()<n)de su elsecláusula, puede elegir si solo desea imprimir / devolver toda la Cadena o manejarla de otra manera.

Matt Boehm
fuente
1
esto corre el riesgo de obtener una IndexOutOfBoundsException
antony.trupe
Por cierto, si planea programar en Java, debe intentar memorizar la mayoría de los métodos API para String ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
Matt Boehm
Ya he descartado la subcadena, al menos por sí sola, ya que no es la respuesta.
antony.trupe
Debe verificar el tamaño o detectar la excepción. ¿Puedo preguntar por qué hacer cualquiera de estos no funcionaría en su situación?
Matt Boehm
3
¿Cómo es esto una respuesta a la pregunta? La pregunta era cómo NO tener que hacer una verificación de tamaño primero, ni causar una excepción que deba detectarse.
ToolmakerSteve
3

Si tienes la suerte de desarrollarte con Kotlin,
puedes usarlo takepara lograr tu objetivo.

val someString = "hello"

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

ApacheCommons me sorprendió, StringUtils.abbreviate(String str, int maxWidth)agrega "..." no hay opción para cambiar postfix. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)mira hacia el siguiente espacio vacío.

Solo voy a dejar esto aquí:

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
fuente
1
@ VolkanGüven Es por esta frase "ApacheCommons me sorprendió". Cometí pecado a través de la biblioteca sagrada de ApacheCommons. O lo que sea ...
yuceel
0

Kotlin: (si alguien lo necesita)

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