Crea una cadena con n caracteres


144

¿Hay alguna manera en Java para crear una cadena con un número específico de un carácter específico? En mi caso, necesitaría crear una cadena con 10 espacios. Mi código actual es:

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

¿Hay una mejor manera de lograr lo mismo? En particular, me gustaría algo que sea rápido (en términos de ejecución).


1
Si te encuentras haciéndolo mucho, solo escribe una función: String characterRepeat (Char c, int Length) {...} que hace lo que haces allí para cualquier carácter y cualquier longitud. Entonces solo llámalo cuando lo necesites.
Austin Fitzpatrick

12
desea utilizar StringBuilder en lugar de StringBuffer

Agregar al principio el tamaño del búfer, es fácil de calcular y facilita la gestión de la memoria. StringBuilder outputBuffer = new StringBuilder (repeat * base.length ());
Victor


Si desea agregar un solo espacio, use append(' ')en su lugar ... implica un poco menos de computación ...
Erk

Respuestas:


36

El compilador optimizará el bucle for. En casos como el suyo, no necesita preocuparse por la optimización por su cuenta. Confía en el compilador.

Por cierto, si hay una manera de crear una cadena con n caracteres de espacio, entonces se codifica de la misma manera que lo hizo.


1
incluso si esto no fue optimizado - con qué frecuencia se crea esto en su programa - si a menudo se guarda en una variable estática u otro caché
mmmmmm

por cierto Array.fill () simplemente recorre la matriz. / yo definitivamente necesito más puntos para comentar en otras publicaciones :)
kalkin

@Mark Length es variable, por lo que parece una tontería guardarlo. ¿Qué haría, tener un static Dictionary<int, String>?
C. Ross

1
Almacenar el más largo que jamás desea la cadena, a continuación, utilizar algo como esto: " ".substring(0, 10);
mjaggard

169

Probablemente el código más corto que utiliza la StringAPI, exclusivamente:

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

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

Como método, sin instanciar directamente 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', ' ' );
}

Invocar usando:

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

44
Aunque me gusta el one-liner, creo que la solución de FrustratedWithFormsDes es mejor cuando se trata de la ejecución, ya que evita verificar cada \ 0 y simplemente asigna el espacio.
Bouncner

1
Probado, esto siempre es más rápido que el bucle, bastante consistentemente 50000-100000 nano segundos más rápido, lo que podría ser bastante significativo (0.1 milisegundos) el bucle se acelera a medida que aumenta el número de iteraciones, aunque el tiempo total sigue siendo alto. Esto es válido para cuando se crean diferentes tamaños de cadenas de espacio.
kmecpp

buscar una solución bastante buena, la he usado en mi respuesta aquí stackoverflow.com/questions/852665/…
maytham-ɯɐɥʇʎɐɯ

66

Hmm, ahora que lo pienso, tal vez Arrays.fill:

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

Por supuesto, supongo que el fillmétodo hace lo mismo que su código, por lo que probablemente funcionará de la misma manera, pero al menos son menos líneas.


2
Después de comprobar la fuente, parece que esto hace, de hecho, hacer exactamente lo que ha escrito el OP: Línea 806 de docjar.com/html/api/java/util/Arrays.java.html
Pops

2
@ Lord Torgamus ¿Se editó la pregunta del OP? Porque en la versión que veo, está haciendo un bucle en StringBuffer.append (), y la versión de Frustrated está haciendo un relleno (que por supuesto realiza bucles haciendo asignaciones de caracteres a la matriz). No es lo mismo en absoluto.
CPerkins

@CPerkins, justo, no estaba claro. Mi punto es que ambos hacen una inserción carácter por carácter dentro de un bucle for.
Aparece

1
@ Lord Torgamus - De acuerdo en eso. lástima que jvm no pueda hacer un memset. Precio que pagamos por caracteres anchos.
CPerkins

2
@Pops vale la pena señalar que si la Arrays.fill()función se usa de manera consistente para hacer este trabajo en su código y en el código de biblioteca (estándar y externo), entonces es un buen candidato para la compilación de Hotspot, y tiene una mejor oportunidad de encontrar su caché de CPU. Las JVM futuras pueden asignarlo como una función intrínseca . Rodar tu propio te corta de toda esta bondad de rendimiento ...
SusanW 05 de

65

Recomiendo no escribir el bucle a mano. Lo harás una y otra vez durante el curso de tu carrera de programación. Las personas que leen su código, eso lo incluye a usted, siempre tienen que invertir tiempo, incluso si son solo unos segundos, para digerir el significado del bucle.

En su lugar, reutilice una de las bibliotecas disponibles que proporcionan código que hace exactamente eso StringUtils.repeatdesde Apache Commons Lang :

StringUtils.repeat(' ', length);

De esa manera, tampoco tiene que preocuparse por el rendimiento, por lo que todos los detalles sangrientos StringBuilder, las optimizaciones del compilador, etc. están ocultos. Si la función resultara lenta, sería un error de la biblioteca.

Con Java 11 se vuelve aún más fácil:

" ".repeat(length);

55
Por otro lado, si StringUtils aún no se usa en el proyecto, agregar otra dependencia para una tarea tan simple podría ser una exageración.
Erich Kitzmueller

1
si resultó lento, también puede enviar su propia corrección para la función.
será el


13

Si solo quieres espacios, entonces ¿qué tal:

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

lo que dará como resultado espacios abs (n);


66
¿Pero cómo es eso de velocidad? Estoy bajo el formato de impresión es relativamente lento. Tiene que analizar la cadena antes de que pueda crearla después de todo.
C. Ross

11

desde Java 11 :

" ".repeat(10);

desde Java 8 :

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

dónde:

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

9

Desde Java 11 simplemente puede usar String.repeat(count)para resolver su problema.

Devuelve una cadena cuyo valor es la concatenación de esta cadena repetida count veces.

Si esta cadena está vacía o countes cero, se devuelve la cadena vacía.

Entonces, en lugar de un bucle, su código se vería así:

" ".repeat(length);

8

Creo que este es el menor código posible, usa la clase Guava Joiner:

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


La línea de código más corta pero agregar una biblioteca grande solo para esa tarea simple no tiene sentido. Puedo crear un JAR más pequeño con un solo método pubic String n(int n) { ... }que permitirá incluso "menos" código: n(10)pero, de nuevo, no tiene ningún sentido.
isapir

@isapir Esta es una gran respuesta para las personas que ya están usando Guava
nasch

1
@nasch Guava no era parte de la pregunta. Pero de todos modos, en 2018 realmente no hay razón para usar Guava's Joiner cuando puedes usar String.join () que se agregó en Java 8. Ver stackoverflow.com/a/43011939/968244
isapir

@isapir No, la guayaba fue una respuesta. Las respuestas en StackOverflow tienen un público más amplio que solo la persona que hace la pregunta, por lo que está bien si algunas respuestas no son las mejores para la persona que hace la pregunta. Y el comentario sobre String.join () es excelente, aunque no estoy seguro de si está disponible en todas las versiones de Android, que es un uso destacado de Java.
nasch

7

Puede usar la String.formatfunción estándar para generar N espacios. Por ejemplo:

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

Hace una cuerda con 5 espacios.

o

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

Hace una cadena de 15 barras espaciales.

Si desea que se repita otro símbolo, debe reemplazar los espacios con su símbolo deseado:

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

Salida:

#######

6

Mi contribución basada en el algoritmo de exponenciación rápida.

/**
 * 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));
}

Probé el algoritmo contra otros dos enfoques:

  • Regular para bucle usando String.concat()para concatenar una cadena
  • Regular para bucle usando un StringBuilder

Código de prueba (concatenación usando un bucle for y se String.concat()vuelve lento para grande n, así que lo dejé fuera después de la quinta iteración).

/**
 * 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);
    }
}

Resultados:

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

Conclusión:

  • Para grandes n: use el enfoque recursivo
  • Para pequeño n: para el bucle tiene suficiente velocidad

44
Esta es una implementación interesante. Desafortunadamente, contrario a sus conclusiones, es muy ineficiente para grandes n. Sospecho que esto se debe a las muchas asignaciones de memoria que ocurren cada vez que concatena cadenas. Intente escribirlo como un contenedor alrededor de un método recursivo que tome StringBuilder en lugar de String. Apuesto a que encontrarás que los resultados serán mucho mejores.
Klitos Kyriacou

3
¡Hay muchas precauciones que debes tomar cuando realices una micro-evaluación comparativa como esta, y no creo que estés tomando ninguna de ellas! Las preguntas de rendimiento dominantes en torno a este código podrían ser fácilmente si está compilado por Hotspot, cuánta basura crea, etc. Apuesto a que todas esas ifdeclaraciones arruinarán la predicción de la rama de la CPU. Esto realmente debería rehacerse usando JMH ( openjdk.java.net/projects/code-tools/jmh ), de lo contrario es un poco inútil.
SusanW

Tenga en cuenta que esta implementación tiene O (n * log n) complejidad, mientras que StringBuilder es O (n) :)
Leo Leontev


4

Considerando que tenemos:

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 (Uso de Stream)

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

Java 8 (usando nCopies)

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

1
Collectors.joining(EMPTY_STRING)es equivalente aCollectors.joining()
PPartisan

2

RandomStringUtils tiene una provisión para crear una cadena a partir del tamaño de entrada dado. No puedo comentar sobre la velocidad, pero es un trazador de líneas.

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

crea una salida

\ t \ t \ t \ t \ t

preferible si no desea ver \ 0 en su código.



1

En la mayoría de los casos, solo necesita cadenas hasta una longitud determinada, digamos 100 espacios. Puede preparar una matriz de cadenas donde el número de índice es igual al tamaño de la cadena llena de espacio y buscar la cadena, si la longitud requerida está dentro de los límites o crearla a pedido si está fuera del límite.



0

Simplemente reemplace su StringBuffer con un StringBuilder . Difícil de superar eso.

Si su longitud es un número grande, podría implementar algunos autoanexos más eficientes (pero más torpes), duplicando la longitud en cada iteración:

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

Además, puede probar el Arrays.fill()enfoque ( la respuesta de FrustratedWithFormsDesigner ).


¿Puedes nombrar algunas de las variables con más de un carácter?
C. Ross

0

Puedes reemplazar StringBufferconStringBuilder (este último no está sincronizado, puede ser más rápido en una aplicación de subproceso único)

Y puede crear la StringBuilderinstancia una vez, en lugar de crearla cada vez que la necesite.

Algo como esto:

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

  }

Y úsalo así:

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

Si mantiene su createAvariable de instancia, puede ahorrar tiempo creando instancias.

Esto no es seguro para subprocesos, si tiene varios subprocesos, cada subproceso debe tener su propia copia.


0

Para un buen rendimiento, combine las respuestas de aznilamir y 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 );
    }
}

Ajuste el tamaño de BLANKSacuerdo con sus requisitos. Mi BLANKScadena específica tiene aproximadamente 200 caracteres de longitud.


0

Tener un método como este. Esto agrega los espacios requeridos al final de lo dado Stringpara hacer una Stringlongitud determinada de una longitud específica.

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

Desea que la cadena sea de tamaño fijo, para que pueda rellenar o truncar, para tabular datos ...

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|

Excelente referencia aquí .


0

Esto funcionó para mí sin usar ninguna biblioteca externa en Java 8

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

Y la salida es

testtesttest

0

int c = 10; Espacios de cadena = String.format ("%" + c + "c", ''); Esto resolverá su problema.


-1

También se puede usar un método simple como el siguiente

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

Esto es sustancialmente más lento.
Fugas

Puede usar StringBuffer en lugar de la concatenación de cadenas, en caso de que las cadenas con las que está tratando sean de gran tamaño. Eso afectará considerablemente la velocidad
Yashpal Singla

-2

¿Qué tal esto?

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

EDITAR: he escrito un código simple para probar el concepto y aquí lo que encontré.

Método 1: agregar espacio único en un bucle:

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

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

    return sb.toString();
  }

Método 2: agregue 100 espacios y bucle, luego subcadena:

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

El resultado que obtengo al crear 12,345,678 espacios:

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

y para 10,000,000 espacios:

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

La combinación de asignación directa e iteración siempre lleva menos tiempo, en promedio 60 ms menos al crear espacios enormes. Para tamaños más pequeños, ambos resultados son insignificantes.

Pero por favor continúe comentando :-)


3
@ aznilamir: Hm, ¿cómo lo harás por 10k espacios?
Jayan

La idea es combinar el bucle y la asignación directa de 100 espacios. Aquí están los fragmentos de código:
aznilamir

¿Por qué utilizas múltiples anexos para agregar 100 caracteres? ¿Por qué no se agregan 100 caracteres?
nycynik

-3

No conozco ningún método integrado para lo que estás preguntando. Sin embargo, para una longitud fija pequeña como 10, su método debería ser bastante rápido.


Si solo fuera una pequeña longitud fija como 10.
C. Ross
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.