Comment puis-je remplir une chaîne en Java?


432

Existe-t-il un moyen simple de remplir les chaînes en Java?

Cela semble être quelque chose qui devrait être dans une API de type StringUtil, mais je ne trouve rien qui fasse cela.


Sur la question de la fonction apache vs le formateur de chaînes, il ne fait aucun doute que la fonction apache est plus claire et plus facile à lire. Envelopper le formateur dans les noms de fonction n'est pas idéal.
Terra Caines

Réponses:


189

Apache StringUtilsa plusieurs méthodes: leftPad, rightPad, centeret repeat.

Mais veuillez noter que - comme d'autres l'ont mentionné et démontré dans cette réponse - String.format()et les Formatterclasses du JDK sont de meilleures options. Utilisez-les sur le code commun.


91
java.util.Formatter (et String.format ()) le fait. Préférez toujours le JDK à une bibliothèque externe si la version du JDK fait le travail (ce qu'il fait).
cletus

6
Pour plusieurs raisons, je préférerais maintenant la goyave à Apache Commons; cette réponse montre comment le faire en goyave .
Jonik

1
@Jonik voudriez-vous énumérer certaines de vos raisons? Les API se ressemblent à peu près.
glen3b

3
@ glen3b: Pour un utilitaire individuel, comme ces aides de remplissage de chaîne, la bibliothèque à utiliser ne fait aucune différence. Cela dit, Guava est dans l'ensemble une bibliothèque plus moderne, plus propre et mieux documentée que ses homologues dans divers projets Apache Commons (Commons Lang, Commons Collections, Commons IO, etc.). Il est également construit par des gars vraiment intelligents (Kevin Bourrillion et al), dont beaucoup sont actifs chez SO . Moi-même, j'ai fini par remplacer les diverses bibliothèques Apache Commons par seulement Guava il y a des années, et je n'ai aucun regret.
Jonik

3
@ glen3b: Quelques bonnes lectures supplémentaires à cette question .
Jonik

635

Depuis Java 1.5, String.format()peut être utilisé pour remplir à gauche / droite une chaîne donnée.

public static String padRight(String s, int n) {
     return String.format("%-" + n + "s", s);  
}

public static String padLeft(String s, int n) {
    return String.format("%" + n + "s", s);  
}

...

public static void main(String args[]) throws Exception {
 System.out.println(padRight("Howto", 20) + "*");
 System.out.println(padLeft("Howto", 20) + "*");
}

Et la sortie est:

Howto               *
               Howto*

39
Et si vous avez besoin de lpad avec d'autres caractères (pas des espaces)? Est-il toujours possible avec String.format? Je ne suis pas en mesure de le faire fonctionner ...
Guido

6
AFAIK String.format () ne peut pas faire ça mais ce n'est pas trop difficile à coder, voir rgagnon.com/javadetails/java-0448.html (2ème exemple)
RealHowTo

61
@ Nullw0rm, si vous faites référence à rgagnon.com, sachez que RealHowTo est aussi l'auteur de rgagnon.com, donc il se créditerait ...
Colin Pickard

3
au moins sur ma JVM, le "#" ne fonctionne pas, le "-" est très bien. (Supprimez simplement le #). Cela peut être cohérent avec la documentation du formateur, je ne sais pas; il dit "'#' '\ u0023' Nécessite que la sortie utilise un autre formulaire. La définition du formulaire est spécifiée par la conversion."
gatoatigrado

6
Merci pour la réponse géniale. J'ai un doute cependant, à quoi ça sert 1$? @leo a fait une réponse très similaire qui n'utilise pas 1$et qui a apparemment le même effet. Est-ce que cela fait une différence?
Fabrício Matté

257

Rembourrage à 10 caractères:

String.format("%10s", "foo").replace(' ', '*');
String.format("%-10s", "bar").replace(' ', '*');
String.format("%10s", "longer than 10 chars").replace(' ', '*');

production:

  *******foo
  bar*******
  longer*than*10*chars

Afficher '*' pour les caractères du mot de passe:

String password = "secret123";
String padded = String.format("%"+password.length()+"s", "").replace(' ', '*');

la sortie a la même longueur que la chaîne de mot de passe:

  secret123
  *********

50
Aussi longtemps que nous nous souvenons tous de ne pas passer dans une chaîne avec des espaces ...: D
leviathanbadger

4
Je suis avec @ aboveyou00 - c'est une solution horrible pour les chaînes avec des espaces, y compris l'exemple fourni par leo. Une solution pour le remplissage d'une chaîne à gauche ou à droite ne doit pas modifier la chaîne d'entrée telle qu'elle apparaît dans la sortie, sauf si le remplissage d'origine de la chaîne d'entrée la fait dépasser la longueur de remplissage spécifiée.
Brian Warshaw

3
Reconnaissez le problème d'espace. .replace(' ', '*')était plutôt destiné à montrer l'effet du rembourrage. L'expression masquant le mot de passe n'a pas ce problème de toute façon ... Pour une meilleure réponse sur la personnalisation de la chaîne de remplissage gauche et droite en utilisant la fonctionnalité Java native, voir mon autre réponse.
leo

Si la chaîne ne contient que des espaces simples et que vous souhaitez ajouter des caractères différents, vous pouvez utiliser regex replace avec look behind / ahead: String.format("%30s", "pad left").replaceAll("(?<=( |^)) ", "*")ouString.format("%-30s", "pad right").replaceAll(" (?=( |$))", "*")
Jaroslaw Pawlak


33

Quelque chose de simple:

La valeur doit être une chaîne. le convertir en chaîne, si ce n'est pas le cas. Comme "" + 123ouInteger.toString(123)

// let's assume value holds the String we want to pad
String value = "123";

La sous-chaîne commence à partir de l'indice de longueur de la valeur de la valeur jusqu'à la longueur de fin du remplissage:

String padded="00000000".substring(value.length()) + value;

// now padded is "00000123"

Plus précis

pad droit:

String padded = value + ("ABCDEFGH".substring(value.length())); 

// now padded is "123DEFGH"

pad gauche:

String padString = "ABCDEFGH";
String padded = (padString.substring(0, padString.length() - value.length())) + value;

// now padded is "ABCDE123"

24

Jetez un oeil à org.apache.commons.lang.StringUtils#rightPad(String str, int size, char padChar).

Mais l'algorithme est très simple (pad jusqu'à la taille des caractères):

public String pad(String str, int size, char padChar)
{
  StringBuffer padded = new StringBuffer(str);
  while (padded.length() < size)
  {
    padded.append(padChar);
  }
  return padded.toString();
}

11
Notez qu'à partir de Java 1.5, cela vaut la peine d'utiliser StringBuilder au lieu de StringBuffer.
Jon Skeet

21

Outre Apache Commons, voyez également String.formatqui devrait être capable de prendre en charge le remplissage simple (par exemple avec des espaces).


17
public static String LPad(String str, Integer length, char car) {
  return (str + String.format("%" + length + "s", "").replace(" ", String.valueOf(car))).substring(0, length);
}

public static String RPad(String str, Integer length, char car) {
  return (String.format("%" + length + "s", "").replace(" ", String.valueOf(car)) + str).substring(str.length(), length + str.length());
}

LPad("Hi", 10, 'R') //gives "RRRRRRRRHi"
RPad("Hi", 10, 'R') //gives "HiRRRRRRRR"
RPad("Hi", 10, ' ') //gives "Hi        "
RPad("Hi", 1, ' ')  //gives "H"
//etc...

4
Faites attention: vous avez inversé les noms des fonctions; si vous l'exécutez, vous verrez.
bleuâtre

De plus, si la chaîne d'origine contient des espaces, cela ne fonctionne pas
Steven Shaw

@StevenShaw Si je ne me trompe pas, le remplacement ne cible pas l'original str, c'est donc correct.
mafu

3
Par convention, vous ne devez pas utiliser de majuscule pour les noms de fonction.
domaine-principal-idéal

Y at - il une condition manquante sur le retour de la chaîne comme est quand (length - str.length())est 0? Le formateur lance un FormatFlagsConversionMismatchExceptionquand %0sest la chaîne de format.
Devin Walters

7

Cela m'a pris un peu de temps pour comprendre. La vraie clé est de lire cette documentation Formatter.

// Get your data from wherever.
final byte[] data = getData();
// Get the digest engine.
final MessageDigest md5= MessageDigest.getInstance("MD5");
// Send your data through it.
md5.update(data);
// Parse the data as a positive BigInteger.
final BigInteger digest = new BigInteger(1,md5.digest());
// Pad the digest with blanks, 32 wide.
String hex = String.format(
    // See: http://download.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html
    // Format: %[argument_index$][flags][width]conversion
    // Conversion: 'x', 'X'  integral    The result is formatted as a hexadecimal integer
    "%1$32x",
    digest
);
// Replace the blank padding with 0s.
hex = hex.replace(" ","0");
System.out.println(hex);

Pourquoi rendre la fin si compliquée? Vous auriez pu juste faire String hex = String.format ("% 032x", digest); et a eu exactement les mêmes résultats, juste sans un replace inutile () et d'avoir à utiliser le $ pour accéder à des variables spécifiques (il n'y en a qu'un, après tout.)
ArtOfWarfare

@ArtOfWarfare fair point. Quelqu'un a initialement demandé le remplissage des valeurs hexadécimales dans une autre question, j'ai vu que j'avais un lien vers la documentation du formateur. C'est compliqué pour être complet.
Nthalk

6

Je sais que ce fil est un peu ancien et la question d'origine était pour une solution facile, mais s'il est censé être très rapide, vous devez utiliser un tableau de caractères.

public static String pad(String str, int size, char padChar)
{
    if (str.length() < size)
    {
        char[] temp = new char[size];
        int i = 0;

        while (i < str.length())
        {
            temp[i] = str.charAt(i);
            i++;
        }

        while (i < size)
        {
            temp[i] = padChar;
            i++;
        }

        str = new String(temp);
    }

    return str;
}

la solution de formateur n'est pas optimale. la construction de la chaîne de formatage crée 2 nouvelles chaînes.

La solution d'Apache peut être améliorée en initialisant le sb avec la taille cible afin de remplacer ci-dessous

StringBuffer padded = new StringBuffer(str); 

avec

StringBuffer padded = new StringBuffer(pad); 
padded.append(value);

empêcherait le tampon interne du sb de croître.


Si StringBuffervous ne pouvez pas accéder à plusieurs threads à la fois (ce qui est vrai dans ce cas), vous devez utiliser un StringBuilder(dans JDK1.5 +) pour éviter la surcharge de synchronisation.
glen3b

5

Voici une autre façon de vous déplacer vers la droite:

// put the number of spaces, or any character you like, in your paddedString

String paddedString = "--------------------";

String myStringToBePadded = "I like donuts";

myStringToBePadded = myStringToBePadded + paddedString.substring(myStringToBePadded.length());

//result:
myStringToBePadded = "I like donuts-------";

5

Depuis Java 11, String.repeat (int) peut être utilisé pour remplir à gauche / droite une chaîne donnée.

System.out.println("*".repeat(5)+"apple");
System.out.println("apple"+"*".repeat(5));

Production:

*****apple
apple*****

1
Meilleure réponse pour Java 11!
Nagy Attila

4

Vous pouvez réduire la surcharge par appel en conservant les données de remplissage, plutôt que de les reconstruire à chaque fois:

public class RightPadder {

    private int length;
    private String padding;

    public RightPadder(int length, String pad) {
        this.length = length;
        StringBuilder sb = new StringBuilder(pad);
        while (sb.length() < length) {
            sb.append(sb);
        }
        padding = sb.toString();
   }

    public String pad(String s) {
        return (s.length() < length ? s + padding : s).substring(0, length);
    }

}

Vous pouvez également faire de la longueur du résultat un paramètre de la pad(...)méthode. Dans ce cas, ajustez le remplissage masqué dans cette méthode plutôt que dans le constructeur.

(Astuce: pour un crédit supplémentaire, rendez-le thread-safe! ;-)


1
C'est sûr pour les threads, sauf pour les publications non sécurisées (rendez vos champs définitifs, bien sûr). Je pense que les performances pourraient être améliorées en faisant une sous-chaîne avant le + qui devrait être remplacée par concat (curieusement).
Tom Hawtin - tackline

3

J'ai trouvé ça sur Dzone

Pad avec zéros:

String.format("|%020d|", 93); // prints: |00000000000000000093|

Cela devrait être la réponse, simple et concise, pas besoin d'installer des bibliothèques externes.
Wong Jia Hau

2

vous pouvez utiliser les méthodes intégrées StringBuilder append () et insert (), pour le remplissage de longueurs de chaîne variables:

AbstractStringBuilder append(CharSequence s, int start, int end) ;

Par exemple:

private static final String  MAX_STRING = "                    "; //20 spaces

    Set<StringBuilder> set= new HashSet<StringBuilder>();
    set.add(new StringBuilder("12345678"));
    set.add(new StringBuilder("123456789"));
    set.add(new StringBuilder("1234567811"));
    set.add(new StringBuilder("12345678123"));
    set.add(new StringBuilder("1234567812234"));
    set.add(new StringBuilder("1234567812222"));
    set.add(new StringBuilder("12345678122334"));

    for(StringBuilder padMe: set)
        padMe.append(MAX_STRING, padMe.length(), MAX_STRING.length());

2

Cela marche:

"".format("%1$-" + 9 + "s", "XXX").replaceAll(" ", "0")

Il remplira votre chaîne XXX jusqu'à 9 caractères avec un espace. Après cela, tous les espaces blancs seront remplacés par un 0. Vous pouvez changer l'espace blanc et le 0 en ce que vous voulez ...


Vous devez invoquer la staticméthode as String.format(…)au lieu d'abuser d'une chaîne vide. L'enregistrement de quatre caractères dans le code source ne vaut certainement pas la perte de lisibilité.
Holger

2
public static String padLeft(String in, int size, char padChar) {                
    if (in.length() <= size) {
        char[] temp = new char[size];
        /* Llenado Array con el padChar*/
        for(int i =0;i<size;i++){
            temp[i]= padChar;
        }
        int posIniTemp = size-in.length();
        for(int i=0;i<in.length();i++){
            temp[posIniTemp]=in.charAt(i);
            posIniTemp++;
        }            
        return new String(temp);
    }
    return "";
}

2

Permettez-moi de laisser une réponse pour certains cas que vous devez donner un remplissage gauche / droite (ou une chaîne de préfixe / suffixe ou des espaces) avant de concaténer une autre chaîne et vous ne voulez pas tester la longueur ou toute condition if.

De même pour la réponse choisie, je préférerais StringUtilsApache Commons mais en utilisant cette façon:

StringUtils.defaultString(StringUtils.leftPad(myString, 1))

Explique:

  • myString: la chaîne que j'entre, peut être nulle
  • StringUtils.leftPad(myString, 1): si la chaîne est nulle, cette instruction retournerait aussi null
  • puis utilisez defaultStringpour donner une chaîne vide pour éviter de concaténer null

2

Les réponses de @ck et @Marlon Tarak sont les seules à utiliser a char[], ce qui est la meilleure approche pour les applications qui ont plusieurs appels aux méthodes de remplissage par seconde. Cependant, ils ne profitent d'aucune optimisation de manipulation de tableau et sont un peu écrasés à mon goût; cela peut être fait sans boucles du tout .

public static String pad(String source, char fill, int length, boolean right){
    if(source.length() > length) return source;
    char[] out = new char[length];
    if(right){
        System.arraycopy(source.toCharArray(), 0, out, 0, source.length());
        Arrays.fill(out, source.length(), length, fill);
    }else{
        int sourceOffset = length - source.length();
        System.arraycopy(source.toCharArray(), 0, out, sourceOffset, source.length());
        Arrays.fill(out, 0, sourceOffset, fill);
    }
    return new String(out);
}

Méthode d'essai simple:

public static void main(String... args){
    System.out.println("012345678901234567890123456789");
    System.out.println(pad("cats", ' ', 30, true));
    System.out.println(pad("cats", ' ', 30, false));
    System.out.println(pad("cats", ' ', 20, false));
    System.out.println(pad("cats", '$', 30, true));
    System.out.println(pad("too long for your own good, buddy", '#', 30, true));
}

Les sorties:

012345678901234567890123456789
cats                          
                          cats
                cats
cats$$$$$$$$$$$$$$$$$$$$$$$$$$
too long for your own good, buddy 

1
Vous pouvez utiliser getCharspour laisser la Stringcopie de son contenu directement dans le outtableau, au lieu d'appeler source.toCharArray(), suivi de System.arraycopy. J'envisagerais même de simplifier la mise en œuvre pour char[] out = new char[length]; Arrays.fill(out, 0, length, fill); source.getChars(0, source.length(), out, right? 0: length - source.length()); return new String(out);; bien que cela semble fillfaire plus de travail, cela permet en fait à la JVM d'éliminer le remplissage par défaut.
Holger

1

java.util.Formatterfera un rembourrage gauche et droit. Pas besoin de dépendances étranges de tiers (voudriez-vous les ajouter pour quelque chose de si trivial).

[J'ai laissé de côté les détails et créé cet article «wiki communautaire» car ce n'est pas quelque chose dont j'ai besoin.]


4
Je ne suis pas d'accord. Dans tout projet Java de plus grande envergure, vous ferez généralement autant de manipulations de chaînes, que la lisibilité accrue et l'évitement des erreurs valent bien l'utilisation d'Apache Commons Lang. Vous connaissez tous du code comme someString.subString (someString.indexOf (startCharacter), someString.lastIndexOf (endCharacter)), ce qui peut facilement être évité avec StringUtils.
Bananeweizen

1

Toutes les opérations de chaîne doivent généralement être très efficaces , en particulier si vous travaillez avec de grands ensembles de données. Je voulais quelque chose de rapide et flexible, similaire à ce que vous obtiendrez dans la commande plsql pad. De plus, je ne veux pas inclure une énorme bibliothèque pour juste une petite chose. Avec ces considérations, aucune de ces solutions n'était satisfaisante. Ce sont les solutions que j'ai trouvées, qui ont eu les meilleurs résultats d'analyse comparative, si quelqu'un peut l'améliorer, veuillez ajouter votre commentaire.

public static char[] lpad(char[] pStringChar, int pTotalLength, char pPad) {
    if (pStringChar.length < pTotalLength) {
        char[] retChar = new char[pTotalLength];
        int padIdx = pTotalLength - pStringChar.length;
        Arrays.fill(retChar, 0, padIdx, pPad);
        System.arraycopy(pStringChar, 0, retChar, padIdx, pStringChar.length);
        return retChar;
    } else {
        return pStringChar;
    }
}
  • notez qu'il est appelé avec String.toCharArray () et que le résultat peut être converti en String avec un nouveau String ((char []) résultat). La raison en est que si vous appliquez plusieurs opérations, vous pouvez toutes les faire sur char [] et ne pas continuer à convertir entre les formats - en arrière-plan, String est stocké en tant que char []. Si ces opérations avaient été incluses dans la classe String elle-même, elles auraient été deux fois plus efficaces - en termes de vitesse et de mémoire.

Cela semble en effet le moyen le plus efficace
David Lilljegren

1

Utilisez cette fonction.

private String leftPadding(String word, int length, char ch) {
   return (length > word.length()) ? leftPadding(ch + word, length, ch) : word;
}

comment utiliser?

leftPadding(month, 2, '0');

sortie: 01 02 03 04 .. 11 12


1

Beaucoup de gens ont des techniques très intéressantes mais j'aime rester simple donc je vais avec ceci:

public static String padRight(String s, int n, char padding){
    StringBuilder builder = new StringBuilder(s.length() + n);
    builder.append(s);
    for(int i = 0; i < n; i++){
        builder.append(padding);
    }
    return builder.toString();
}

public static String padLeft(String s, int n,  char padding) {
    StringBuilder builder = new StringBuilder(s.length() + n);
    for(int i = 0; i < n; i++){
        builder.append(Character.toString(padding));
    }
    return builder.append(s).toString();
}

public static String pad(String s, int n, char padding){
    StringBuilder pad = new StringBuilder(s.length() + n * 2);
    StringBuilder value = new StringBuilder(n);
    for(int i = 0; i < n; i++){
        pad.append(padding);
    }
    return value.append(pad).append(s).append(pad).toString();
}

2
Ceci est très inefficace, vous devez utiliser un StringBuilder
wkarl

Puisque vous connaissez déjà la longueur, vous devez dire au StringBuilder d'allouer autant d'espace lorsque vous l'instanciez.
Ariel

@Ariel intéressant que vous mentionniez cela parce que je parlais juste à quelqu'un d'autre à ce sujet aujourd'hui lol.
Aelphaeis

0

Une solution simple sans aucune API sera la suivante:

public String pad(String num, int len){
    if(len-num.length() <=0) return num;
    StringBuffer sb = new StringBuffer();
    for(i=0; i<(len-num.length()); i++){
        sb.append("0");
    }
    sb.append(num);
    return sb.toString();
}

0

Oneliners Java, pas de bibliothèque de fantaisie.

// 6 characters padding example
String pad = "******";
// testcases for 0, 4, 8 characters
String input = "" | "abcd" | "abcdefgh"

Pad gauche, ne pas limiter

result = pad.substring(Math.min(input.length(),pad.length())) + input;
results: "******" | "**abcd" | "abcdefgh"

Pad Right, ne pas limiter

result = input + pad.substring(Math.min(input.length(),pad.length()));
results: "******" | "abcd**" | "abcdefgh"

Pad gauche, limite à la longueur du pad

result = (pad + input).substring(input.length(), input.length() + pad.length());
results: "******" | "**abcd" | "cdefgh"

Pad Right, limite à la longueur du pad

result = (input + pad).substring(0, pad.length());
results: "******" | "abcd**" | "abcdef"

0

Que diriez-vous d'utiliser la récursivité? La solution donnée ci-dessous est compatible avec toutes les versions JDK et aucune bibliothèque externe requise :)

private static String addPadding(final String str, final int desiredLength, final String padBy) {
        String result = str;
        if (str.length() >= desiredLength) {
            return result;
        } else {
            result += padBy;
            return addPadding(result, desiredLength, padBy);
        }
    }

REMARQUE : Cette solution ajoutera le remplissage, avec un petit ajustement, vous pouvez préfixer la valeur du tampon.


0

Voici une version parallèle pour ceux d'entre vous qui ont de très longues cordes :-)

int width = 100;
String s = "129018";

CharSequence padded = IntStream.range(0,width)
            .parallel()
            .map(i->i-(width-s.length()))
            .map(i->i<0 ? '0' :s.charAt(i))
            .collect(StringBuilder::new, (sb,c)-> sb.append((char)c), (sb1,sb2)->sb1.append(sb2));

0

-1

Une solution simple serait:

package nl;
public class Padder {
    public static void main(String[] args) {
        String s = "123" ;
        System.out.println("#"+("     " + s).substring(s.length())+"#");
    }
}

-1

Comment est-ce

La chaîne est "bonjour" et le remplissage requis est de 15 avec le tampon gauche "0"

String ax="Hello";
while(ax.length() < 15) ax="0"+ax;

10
celui-ci génère jusqu'à 15 nouvelles chaînes.
claj

@claj Oui, mais ça .
ruffin
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.