Comment obtenir les n premiers caractères d'une chaîne sans vérifier la taille ni sortir des limites?


163

Comment obtenir les premiers ncaractères d'une chaîne en Java sans faire d'abord une vérification de la taille (en ligne est acceptable) ou risquer un IndexOutOfBoundsException?


1
sauf si vous attrapez l'exception, je ne sais pas comment vous prévoyez de gérer le cas où la longueur des caractères est supérieure à la longueur de la chaîne.
Matt Boehm

2
Pourquoi? Quelle est votre aversion pour vérifier la longueur ou attraper une exception?
paxdiablo

1
Par curiosité, pourquoi voulez-vous éviter le contrôle de taille. This is not C.
Tom Hawtin - Tackline

ce que je voulais exprimer était un désir d'éviter un bloc if / else, pas une aversion pour vérifier réellement la longueur.
antony.trupe

Réponses:


347

Voici une solution intéressante:

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

Opinion: si cette solution est "soignée", je pense qu'elle est en fait moins lisible qu'une solution qui utilise if/ elsede manière évidente. Si le lecteur n'a pas vu cette astuce, il doit réfléchir plus fort pour comprendre le code. IMO, la signification du code est plus évidente dans la version if/ else. Pour une solution plus propre / plus lisible, voir la réponse de @ paxdiablo.


1
+1. Encore mieux si cela est enveloppé dans une fonction nommée safe_substring ou substring_safe, comme la réponse de paxdiablo, afin que l'utilisation soit plus facile à lire / l'intention plus évidente.
ToolmakerSteve

Je ne suis pas d'accord avec ce que vous dites. Si cela est enveloppé dans une fonction, peu importe ce qu'il y a à l'intérieur de la fonction , et toute "netteté" est définitivement surpassée par le manque de clarté. L'intérêt de cette solution est qu'elle est "soignée" dans le cas où vous ne souhaitez pas créer de fonction wrapper.
Stephen C

88

Ne réinventez pas la roue ...:

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

Javadoc dit:

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"

Donc:

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

1
Il ne répond pas à la question, mais quoi qu'il en soit, il fournit toujours la solution. Si le PO est capable de comprendre, je pense que c'est une meilleure solution.
aullah

5
Il pourrait également être utile de souligner que ce StringUtils.substring(yourString, 0, n)n'est pas la même chose que yourString.substring(0, n). Le premier est de StringUtils, tandis que le second utilise String.substring(ce qui donne une exception si l'index de fin dépasse la longueur de la chaîne).
ToolmakerSteve

Tout comme FYI si vous regardez dans la source pour cette méthode, il gère le cas où la fin est supérieure à la longueur en changeant la fin en longueur:if (end > str.length()) { end = str.length();}
bholl

1
Le dernier paramètre de StringUtils.substring(String s, int start, int len)n'est pas len, c'est l'index de fin.
gorootde

StringUtils.substring ("abc", 0, 4) = "abc", a fonctionné pour moi. Merci !
Akash5288

42

Apache Commons Lang a une StringUtils.leftméthode pour cela.

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

Cela ne devrait-il pas être la meilleure solution? Pourquoi n'y a-t-il pas beaucoup de votes positifs?
Do Will

3
Peut-être parce que d'autres personnes n'ont pas la même opinion que vous? :-)
Stephen C

cette réponse est arrivée beaucoup plus tard que la date de la question initiale.
Mulki

@DoWill: Parce que l'ajout d'une (autre) bibliothèque tierce à votre environnement exécutable ne vaut pas toujours la peine.
LarsH

12

Il y a une classe de questions sur SO qui n'a parfois pas de sens, celle-ci est dangereusement proche :-)

Peut-être pourriez-vous expliquer votre aversion à l’utilisation de l’une des deux méthodes que vous avez exclues.

Si c'est simplement parce que vous ne voulez pas poivrer votre code avec des ifinstructions ou du code de capture d'exceptions, une solution consiste à utiliser une fonction d'assistance qui s'en chargera pour vous, quelque chose comme:

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

qui vérifiera les longueurs au préalable et agira en conséquence (retourne une chaîne plus petite ou un pad avec des espaces).

Ensuite, vous n'avez pas du tout à vous en soucier dans votre code, appelez simplement:

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

au lieu de:

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

Cela fonctionnerait dans le cas où vous semblez être inquiet (en fonction de vos commentaires sur d'autres réponses), ne pas briser le flux du code lorsque vous faites beaucoup de choses de construction de chaînes.


1
Vous devriez lire le commentaire de plus près, @antony, en particulier le smiley, et ne pas être si précieux pour ceux qui essaient d'aider. Je disais simplement que vous n'aviez pas expliqué pourquoi vous deviez éviter les deux méthodes. Et c'est une vraie réponse, utilisant une fonction d'assistance, c'est pourquoi ce n'est pas dans un commentaire.
paxdiablo

1
+1: C'est une approche BIEN meilleure que celle acceptée, étant donné le désir d'OP de ne pas encombrer le code. (ou voir la solution de Nickkk d'inclure une bibliothèque qui a déjà une fonction qui se comporte comme vous le souhaitez.)
ToolmakerSteve

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

Horrible si nest une variable (vous devez donc construire la chaîne de format), mais assez clair si une constante:

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

docs


Alternative intéressante, même si je ne peux pas imaginer l'utiliser, étant donné les approches plus traditionnelles, qui ont été données il y a quatre ans.
ToolmakerSteve

Meilleure réponse car la chaîne d'entrée n'est lue qu'une seule fois, il n'est donc pas nécessaire de la stocker dans une variable, ce qui permet de l'intégrer proprement.
Profiterole

3

Utilisez la méthode substring, comme suit:

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

Si n est supérieur à la longueur de la chaîne, cela lèvera une exception, comme l'a souligné un commentateur. une solution simple consiste à envelopper tout cela dans la condition if(s.length()<n)de votre elseclause, vous pouvez choisir si vous voulez simplement imprimer / renvoyer la chaîne entière ou la gérer d'une autre manière.


1
cela risque d'obtenir une IndexOutOfBoundsException
antony.trupe

En passant, si vous prévoyez de programmer en Java, vous devriez essayer de mémoriser la plupart des méthodes API pour String ( java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html ).
Matt Boehm

J'ai déjà exclu la sous-chaîne, au moins seule, comme n'étant pas la réponse.
antony.trupe

Vous devez soit vérifier la taille, soit attraper l'exception. Puis-je vous demander pourquoi faire l'un ou l'autre de ces éléments ne fonctionnerait pas dans votre situation?
Matt Boehm

3
En quoi est-ce une réponse à la question? La question était de savoir comment NE PAS avoir à faire un contrôle de taille en premier, ni provoquer une exception qui doit être interceptée.
ToolmakerSteve

3

Si vous avez la chance de développer avec Kotlin,
vous pouvez l'utiliser takepour atteindre votre objectif.

val someString = "hello"

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

0

ApacheCommons m'a surpris, StringUtils.abbreviate(String str, int maxWidth)ajoute "..." il n'y a pas d'option pour changer le suffixe. WordUtils.abbreviate(String str, int lower, int upper, String appendToEnd)regarde le prochain espace vide.

Je vais juste laisser ceci ici:

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 C'est à cause de cette phrase "ApacheCommons m'a surpris". J'ai commis le péché en critiquant la bibliothèque sainte ApacheCommons. Ou peu importe ...
yuceel

0

Kotlin: (Si quelqu'un a besoin)

var mText = text.substring(0, text.length.coerceAtMost(20))
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.