Créer une chaîne avec n caractères


144

Existe-t-il un moyen en java de créer une chaîne avec un nombre spécifié d'un caractère spécifié? Dans mon cas, j'aurais besoin de créer une chaîne de 10 espaces. Mon code actuel est:

StringBuffer outputBuffer = new StringBuffer(length);
for (int i = 0; i < length; i++){
   outputBuffer.append(" ");
}
return outputBuffer.toString();

Y a-t-il une meilleure façon d'accomplir la même chose? En particulier, j'aimerais quelque chose de rapide (en termes d'exécution).


1
Si vous vous trouvez en train de le faire beaucoup, écrivez simplement une fonction: String characterRepeat (Char c, int Length) {...} qui fait ce que vous faites là pour n'importe quel caractère et n'importe quelle longueur. Alors appelez-le quand vous en avez besoin.
Austin Fitzpatrick

12
vous voulez utiliser StringBuilder au lieu de StringBuffer

Ajouter au début la taille du tampon, est facile à calculer et facilite les choses dans la gestion de la mémoire !. StringBuilder outputBuffer = new StringBuilder (repeat * base.length ());
Victor le


Si vous souhaitez ajouter un seul espace, utilisez à la append(' ')place ... cela implique un peu moins de calcul ...
Erk

Réponses:


36

La boucle for sera optimisée par le compilateur. Dans des cas comme le vôtre, vous n'avez pas besoin de vous soucier de l'optimisation par vous-même. Faites confiance au compilateur.

BTW, s'il existe un moyen de créer une chaîne avec n caractères d'espace, elle est codée de la même manière que vous venez de le faire.


1
même si cela n'a pas été optimisé - à quelle fréquence est-ce créé dans votre programme - si souvent enregistré dans une variable statique ou un autre cache
mmmmmm

btw Array.fill () boucle juste à travers le tableau. / moi j'ai besoin de plus de points pour commenter les autres articles :)
kalkin

@Mark Length est variable, il semble donc ridicule de le sauvegarder. Que ferais-je, avoir un static Dictionary<int, String>?
C. Ross

1
Stockez le plus longtemps que vous voudrez la chaîne, puis utilisez quelque chose comme ceci: " ".substring(0, 10);
mjaggard

169

Probablement le code le plus court utilisant l' StringAPI, exclusivement:

String space10 = new String(new char[10]).replace('\0', ' ');

System.out.println("[" + space10 + "]");
// prints "[          ]"

En tant que méthode, sans instancier directement char:

import java.nio.CharBuffer;

/**
 * Creates a string of spaces that is 'spaces' spaces long.
 *
 * @param spaces The number of spaces to add to the string.
 */
public String spaces( int spaces ) {
  return CharBuffer.allocate( spaces ).toString().replace( '\0', ' ' );
}

Appeler en utilisant:

System.out.printf( "[%s]%n", spaces( 10 ) );

4
Même si j'aime le one-liner, je pense que la solution de FrustratedWithFormsDes est la meilleure en ce qui concerne l'exécution car elle évite de vérifier chacun pour \ 0 et attribue simplement l'espace.
Bouncner

1
Testé, c'est toujours plus rapide que la boucle, assez régulièrement 50000-100000 nano secondes plus rapide, ce qui pourrait être assez important (0,1 milliseconde) la boucle devient plus rapide à mesure que le nombre d'itérations augmente bien que le temps total soit encore élevé. Cela est vrai lors de la création de différentes tailles de chaînes d'espace.
kmecpp

thump up for pretty nice solution, je l'ai utilisé dans ma réponse ici stackoverflow.com/questions/852665/…
maytham-ɯɐɥʇʎɐɯ

66

Hmm maintenant que j'y pense, peut-être Arrays.fill:

char[] charArray = new char[length];
Arrays.fill(charArray, ' ');
String str = new String(charArray);

Bien sûr, je suppose que la fillméthode fait la même chose que votre code, donc elle fonctionnera probablement à peu près de la même manière, mais au moins, il y a moins de lignes.


2
Après vérification de la source, il semble que cela fasse en fait exactement ce que l'OP a publié: ligne 806 de docjar.com/html/api/java/util/Arrays.java.html
Pops

2
@Lord Torgamus La question du PO a-t-elle été modifiée? Parce que dans la version que je vois, il boucle sur StringBuffer.append (), et la version de Frustrated fait un remplissage (qui, bien sûr, boucle des affectations de caractères au tableau). Pas du tout la même chose.
CPerkins

@CPerkins, c'est juste, je n'ai pas été clair. Mon point est que les deux font une insertion caractère par caractère à l'intérieur d'une boucle for.
Pops

1
@Lord Torgamus - D'accord. dommage que le jvm ne puisse pas simplement faire un memset. Prix ​​que nous payons pour des caractères larges.
CPerkins

2
@Pops, il convient de noter que si la Arrays.fill()fonction est utilisée de manière cohérente pour effectuer ce travail dans votre code et dans le code de la bibliothèque (standard et externe), elle constitue un bon candidat pour la compilation Hotspot et a de meilleures chances de trouver le cache de votre processeur. Les futures machines virtuelles Java peuvent l'attribuer en tant que fonction intrinsèque . Rouler vous-même vous coupe de toute cette bonté de performance ...
SusanW

65

Je suggère fortement de ne pas écrire la boucle à la main. Vous ferez cela encore et encore au cours de votre carrière en programmation. Les personnes qui lisent votre code - vous y compris - doivent toujours investir du temps, même si ce ne sont que quelques secondes, pour digérer le sens de la boucle.

Au lieu de cela, réutilisez l' une des bibliothèques disponibles fournissant du code qui fait exactement cela comme StringUtils.repeatdans Apache Commons Lang :

StringUtils.repeat(' ', length);

De cette façon, vous n'avez pas non plus à vous soucier des performances, donc tous les détails sanglants des StringBuilderoptimisations du compilateur, etc. sont cachés. Si la fonction s'avérait aussi lente, ce serait un bogue de la bibliothèque.

Avec Java 11, cela devient encore plus simple:

" ".repeat(length);

5
D'un autre côté, si StringUtils n'est pas déjà utilisé dans le projet, l'ajout d'une autre dépendance pour une tâche aussi simple peut être excessif.
Erich Kitzmueller

1
si cela s'avère lent, vous pouvez également soumettre votre propre correctif pour la fonction.
sera


13

Si vous ne voulez que des espaces, que diriez-vous:

String spaces = (n==0)?"":String.format("%"+n+"s", "");

ce qui se traduira par des espaces abs (n);


6
Mais qu'en est-il de la vitesse? Je suis sous le format d'impression est relativement lent. Il doit analyser la chaîne avant de pouvoir la créer après tout.
C. Ross

11

depuis Java 11 :

" ".repeat(10);

depuis Java 8 :

generate(() -> " ").limit(10).collect(joining());

où:

import static java.util.stream.Collectors.joining;
import static java.util.stream.Stream.generate;

9

Depuis Java 11, vous pouvez simplement utiliser String.repeat(count)pour résoudre votre problème.

Renvoie une chaîne dont la valeur est la concaténation de cette chaîne répétée plusieurs countfois.

Si cette chaîne est vide ou countvaut zéro, la chaîne vide est renvoyée.

Donc, au lieu d'une boucle, votre code ressemblerait à ceci:

" ".repeat(length);

8

Je pense que c'est le moins de code possible, il utilise la classe Guava Joiner:

Joiner .on (""). Join ( Collections.nCopies (10, ""));


La ligne de code la plus courte mais l'ajout d'une grande bibliothèque juste pour cette tâche simple n'a pas de sens. Je peux créer moi-même un JAR plus petit avec une seule méthode pubic String n(int n) { ... }qui permettra encore "moins" de code:, n(10)mais encore une fois, cela n'a aucun sens.
isapir le

@isapir C'est une excellente réponse pour les personnes qui utilisent déjà Guava
nasch

1
@nasch Guava ne faisait pas partie de la question. Mais de toute façon, en 2018, il n'y a vraiment aucune raison d'utiliser Guava's Joiner lorsque vous pouvez utiliser String.join () qui a été ajouté à Java 8. Voir stackoverflow.com/a/43011939/968244
isapir

@isapir Non, Guava était une réponse. Les réponses sur StackOverflow ont un public plus large que la seule personne qui pose la question, donc c'est bien si certaines réponses ne sont pas les meilleures pour la personne qui pose la question. Et le commentaire sur String.join () est excellent, même si je ne suis pas sûr qu'il soit disponible sur toutes les versions d'Android, ce qui est une utilisation importante de Java.
nasch

7

Vous pouvez utiliser la String.formatfonction standard pour générer N espaces. Par exemple:

String.format("%5c", ' ');

Crée une chaîne de 5 espaces.

ou

int count = 15;
String fifteenSpacebars = String.format("%" + count + "c", ' ');

Donne une chaîne de 15 barres d'espace.

Si vous souhaitez qu'un autre symbole se répète, vous devez remplacer les espaces par le symbole souhaité:

int count = 7;
char mySymbol = '#';
System.out.println(String.format("%" + count + "c", ' ').replaceAll("\\ ", "\\" + mySymbol));

Production:

#######

6

Ma contribution basée sur l'algorithme d'exponentiation rapide.

/**
 * Repeats the given {@link String} n times.
 * 
 * @param str
 *            the {@link String} to repeat.
 * @param n
 *            the repetition count.
 * @throws IllegalArgumentException
 *             when the given repetition count is smaller than zero.
 * @return the given {@link String} repeated n times.
 */
public static String repeat(String str, int n) {
    if (n < 0)
        throw new IllegalArgumentException(
                "the given repetition count is smaller than zero!");
    else if (n == 0)
        return "";
    else if (n == 1)
        return str;
    else if (n % 2 == 0) {
        String s = repeat(str, n / 2);
        return s.concat(s);
    } else
        return str.concat(repeat(str, n - 1));
}

J'ai testé l'algorithme par rapport à deux autres approches:

  • Boucle for régulière utilisant String.concat()pour concaténer une chaîne
  • Boucle for régulière utilisant un StringBuilder

Code de test (concaténation utilisant une boucle for et String.concat()devient ntrop lente pour un grand , donc je l'ai laissé de côté après la 5ème itération).

/**
 * Test the string concatenation operation.
 * 
 * @param args
 */
public static void main(String[] args) {
    long startTime;
    String str = " ";

    int n = 1;
    for (int j = 0; j < 9; ++j) {
        n *= 10;
        System.out.format("Performing test with n=%d\n", n);

        startTime = System.currentTimeMillis();
        StringUtil.repeat(str, n);
        System.out
                .format("\tStringUtil.repeat() concatenation performed in    %d milliseconds\n",
                        System.currentTimeMillis() - startTime);

        if (j <5) {
            startTime = System.currentTimeMillis();
            String string = "";
            for (int i = 0; i < n; ++i)
                string = string.concat(str);
            System.out
                    .format("\tString.concat() concatenation performed in        %d milliseconds\n",
                            System.currentTimeMillis() - startTime);
        } else
            System.out
                    .format("\tString.concat() concatenation performed in        x milliseconds\n");
        startTime = System.currentTimeMillis();
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < n; ++i)
            b.append(str);
        b.toString();
        System.out
                .format("\tStringBuilder.append() concatenation performed in %d milliseconds\n",
                        System.currentTimeMillis() - startTime);
    }
}

Résultats:

Performing test with n=10
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        0 milliseconds
    StringBuilder.append() concatenation performed in 0 milliseconds
Performing test with n=100
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1 milliseconds
    StringBuilder.append() concatenation performed in 0 milliseconds
Performing test with n=1000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1 milliseconds
    StringBuilder.append() concatenation performed in 1 milliseconds
Performing test with n=10000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        43 milliseconds
    StringBuilder.append() concatenation performed in 5 milliseconds
Performing test with n=100000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        1579 milliseconds
    StringBuilder.append() concatenation performed in 1 milliseconds
Performing test with n=1000000
    StringUtil.repeat() concatenation performed in    0 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 10 milliseconds
Performing test with n=10000000
    StringUtil.repeat() concatenation performed in    7 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 112 milliseconds
Performing test with n=100000000
    StringUtil.repeat() concatenation performed in    80 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 1107 milliseconds
Performing test with n=1000000000
    StringUtil.repeat() concatenation performed in    1372 milliseconds
    String.concat() concatenation performed in        x milliseconds
    StringBuilder.append() concatenation performed in 12125 milliseconds

Conclusion:

  • Pour les grands n- utilisez l'approche récursive
  • Pour les petits n- la boucle for a une vitesse suffisante

4
C'est une implémentation intéressante. Malheureusement, contrairement à vos conclusions, il est très inefficace pour un grand n. Je soupçonne que cela est dû aux nombreuses allocations de mémoire qui se produisent chaque fois que vous concaténez des chaînes. Essayez de l'écrire comme un wrapper autour d'une méthode récursive qui prend StringBuilder au lieu de String. Je parie que vous trouverez que les résultats seront bien meilleurs.
Klitos Kyriacou

3
Il y a beaucoup de précautions à prendre lors du micro-benchmarking de quelque chose comme ça, et je ne pense pas que vous en preniez une! Les questions de performances dominantes autour de ce code pourraient facilement être de savoir s'il est compilé par Hotspot, combien de déchets il crée, etc. Je parie que toutes ces ifdéclarations vont gâcher la prédiction de branche du CPU. Cela devrait vraiment être refait à l'aide de JMH ( openjdk.java.net/projects/code-tools/jmh ), sinon c'est un peu inutile.
SusanW

Notez que cette implémentation a une complexité O (n * log n), tandis que StringBuilder est O (n) :)
Leo Leontev


4

Considérant que nous avons:

String c = "c"; // character to repeat, for empty it would be " ";
int n = 4; // number of times to repeat
String EMPTY_STRING = ""; // empty string (can be put in utility class)

Java 8 (en utilisant Stream)

String resultOne = IntStream.range(0,n)
   .mapToObj(i->c).collect(Collectors.joining(EMPTY_STRING)); // cccc

Java 8 (avec nCopies)

String resultTwo = String.join(EMPTY_STRING, Collections.nCopies(n, c)); //cccc

1
Collectors.joining(EMPTY_STRING)équivaut àCollectors.joining()
PPartisan

2

RandomStringUtils a une disposition pour créer une chaîne à partir d'une taille d'entrée donnée. Je ne peux pas faire de commentaire sur la vitesse, mais c'est une ligne unique.

RandomStringUtils.random(5,"\t");

crée une sortie

\ t \ t \ t \ t \ t

préférable si vous ne voulez pas voir \ 0 dans votre code.



1

Dans la plupart des cas, vous n'avez besoin que de chaînes jusqu'à une certaine longueur, disons 100 espaces. Vous pouvez préparer un tableau de chaînes où le numéro d'index est égal à la taille de la chaîne remplie d'espace et rechercher la chaîne, si la longueur requise est dans les limites ou la créer à la demande si elle est en dehors de la limite.



0

Remplacez simplement votre StringBuffer par un StringBuilder . Difficile de battre ça.

Si votre longueur est un grand nombre, vous pouvez implémenter un auto-ajout plus efficace (mais plus maladroit), en dupliquant la longueur à chaque itération:

 public static String dummyString(char c, int len) {
  if( len < 1 ) return "";
  StringBuilder sb = new StringBuilder(len).append(c);
  int remnant = len - sb.length();
  while(remnant  > 0) {
   if( remnant  >= sb.length() ) sb.append(sb);
   else sb.append(sb.subSequence(0, remnant));
   remnant  = len - sb.length();
  }
  return sb.toString();
 }

Vous pouvez également essayer l ' Arrays.fill()approche ( réponse de FrustratedWithFormsDesigner ).


Pouvez-vous nommer certaines des variables plus d'un caractère?
C. Ross

0

Vous pouvez remplacer StringBufferpar StringBuilder(ce dernier n'est pas synchronisé, peut être plus rapide dans une seule application de thread)

Et vous pouvez créer l' StringBuilderinstance une fois, au lieu de la créer chaque fois que vous en avez besoin.

Quelque chose comme ça:

class BuildString {
     private final StringBuilder builder = new StringBuilder();
     public String stringOf( char c , int times ) {

         for( int i = 0 ; i < times ; i++  ) {
             builder.append( c );
         }
         String result = builder.toString();
         builder.delete( 0 , builder.length() -1 );
         return result;
      }

  }

Et utilisez-le comme ceci:

 BuildString createA = new BuildString();
 String empty = createA.stringOf( ' ', 10 );

Si vous conservez votre createAcomme variable d'instance, vous pouvez gagner du temps en créant des instances.

Ce n'est pas thread-safe, si vous avez plusieurs threads, chaque thread doit avoir sa propre copie.


0

Pour de bonnes performances, combinez les réponses d' aznilamir et de FrustratedWithFormsDesigner

private static final String BLANKS = "                       ";
private static String getBlankLine( int length )
{
    if( length <= BLANKS.length() )
    {
        return BLANKS.substring( 0, length );
    }
    else
    {
        char[] array = new char[ length ];
        Arrays.fill( array, ' ' );
        return new String( array );
    }
}

Ajustez la taille de en BLANKSfonction de vos besoins. Ma BLANKSchaîne spécifique est d'environ 200 caractères.


0

Ayez une méthode comme celle-ci. Cela ajoute les espaces requis à la fin de la donnée Stringpour donner une Stringlongueur donnée à une longueur spécifique.

public static String fillSpaces (String str) {

    // the spaces string should contain spaces exceeding the max needed
    String spaces = "                                                   ";
    return str + spaces.substring(str.length());
}

0

Vous voulez que la chaîne soit de taille fixe, de sorte que vous remplissiez ou tronquiez, pour tabuler les données ...

class Playground {
    private static String fixStrSize(String s, int n) {
        return String.format("%-" + n + "s", String.format("%." + n +"s", s));
    }

    public static void main(String[ ] args) {
        System.out.println("|"+fixStrSize("Hell",8)+"|");
        System.out.println("|"+fixStrSize("Hells Bells Java Smells",8)+"|");
    }
}

|Hell    |
|Hells Be|

Excellente référence ici .


0

Cela a fonctionné pour moi sans utiliser de bibliothèques externes dans Java 8

String sampleText = "test"
int n = 3;
String output = String.join("", Collections.nCopies(n, sampleText));
System.out.println(output);

Et la sortie est

testtesttest

0

int c = 10; Espaces de chaîne = String.format ("%" + c + "c", ''); cela résoudra votre problème.


-1

Une méthode simple comme ci-dessous peut également être utilisée

public static String padString(String str, int leng,char chr) {
        for (int i = str.length(); i <= leng; i++)
            str += chr;
        return str;
    }

Ceci est sensiblement plus lent.
SLaks

Vous pouvez utiliser StringBuffer au lieu de la concaténation de chaînes, au cas où les chaînes que vous traitez sont de grande taille. Cela aura un impact considérable sur la vitesse
Yashpal Singla

-2

que dis-tu de ça?

public String fillSpaces(int len) {
    /* the spaces string should contain spaces exceeding the max needed */  
    String spaces = "                                                   ";
    return spaces.substring(0,len);
}

EDIT: j'ai écrit un code simple pour tester le concept et voici ce que j'ai trouvé.

Méthode 1: ajouter un seul espace dans une boucle:

  public String execLoopSingleSpace(int len){
    StringBuilder sb = new StringBuilder();

    for(int i=0; i < len; i++) {
        sb.append(' ');
    }

    return sb.toString();
  }

Méthode 2: ajoutez 100 espaces et boucle, puis sous-chaîne:

  public String execLoopHundredSpaces(int len){
    StringBuilder sb = new StringBuilder("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ");

    for (int i=0; i < len/100 ; i++) {
        sb.append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ")
            .append("          ").append("          ").append("          ");
    }

    return sb.toString().substring(0,len);
  }

Le résultat que j'obtiens en créant 12345678 espaces:

C:\docs\Projects> java FillSpace 12345678
method 1: append single spaces for 12345678 times. Time taken is **234ms**. Length of String is 12345678
method 2: append 100 spaces for 123456 times. Time taken is **141ms**. Length of String is 12345678
Process java exited with code 0

et pour 10 000 000 places:

C:\docs\Projects> java FillSpace 10000000
method 1: append single spaces for 10000000 times. Time taken is **157ms**. Length of String is 10000000
method 2: append 100 spaces for 100000 times. Time taken is **109ms**. Length of String is 10000000
Process java exited with code 0

combiner l'allocation directe et l'itération prend toujours moins de temps, en moyenne 60 ms de moins lors de la création de grands espaces. Pour les plus petites tailles, les deux résultats sont négligeables.

Mais veuillez continuer à commenter :-)


3
@ aznilamir: Hm, comment ferez-vous pour 10k espaces?
Jayan

L'idée est de combiner boucle et allocation directe de 100 espaces. Voici les extraits de code:
aznilamir

Pourquoi utilisez-vous plusieurs ajouts pour ajouter 100 caractères? Pourquoi pas un ajout de 100 caractères?
nycynik

-3

Je ne connais aucune méthode intégrée pour ce que vous demandez. Cependant, pour une petite longueur fixe comme 10, votre méthode devrait être très rapide.


Si seulement c'était une petite longueur fixe comme 10.
C. Ross
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.