Crie uma sequência com n caracteres


144

Existe uma maneira no java de criar uma string com um número especificado de um caractere especificado? No meu caso, eu precisaria criar uma string com 10 espaços. Meu código atual é:

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

Existe uma maneira melhor de realizar a mesma coisa. Em particular, eu gostaria de algo rápido (em termos de execução).


1
Se você estiver fazendo isso muito, basta escrever uma função: String characterRepeat (Char c, int Length) {...} que faz o que você faz lá para qualquer caractere e qualquer tamanho. Depois, basta ligar quando precisar.
Austin Fitzpatrick

12
você deseja usar StringBuilder em vez de StringBuffer

Adicionar no início o tamanho do buffer, é fácil calcular e facilita as coisas na gestão de memória !. StringBuilder outputBuffer = new StringBuilder (repita * base.length ());
Victor


Se você deseja anexar um único espaço, use append(' ')em vez ... que envolve um pouco menos de computação ...
Erk

Respostas:


36

O loop for será otimizado pelo compilador. Nesses casos, como o seu, você não precisa se preocupar com a otimização por conta própria. Confie no compilador.

BTW, se houver uma maneira de criar uma string com n caracteres de espaço, ela será codificada da mesma maneira que você criou.


1
mesmo que isso não foi otimizado - quantas vezes é isso criou em seu programa - se, muitas vezes, salvo em uma variável estática ou outro esconderijo
mmmmmm

btw Array.fill () apenas circula pela matriz. / precisar de mim definitivamente mais pontos a comentar sobre outras mensagens :)
kalkin

@ Mark Length é variável, por isso parece bobagem salvá-lo. O que eu faria, tenho um static Dictionary<int, String>?
C. Ross

1
Armazene o maior tempo que você desejar para a string e use algo parecido com isto: " ".substring(0, 10);
mjaggard

169

Provavelmente o código mais curto usando a StringAPI, exclusivamente:

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

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

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

Invoque usando:

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

4
Embora eu goste do one-liner, acho que a solução do FrustratedWithFormsDes é a melhor quando se trata de execução, pois evita a verificação de cada um por \ 0 e simplesmente atribui o espaço.
Bouncner

1
Testado, isso é sempre mais rápido que o loop, consistentemente 50000-100000 nano segundos mais rápido, o que pode ser bastante significativo (0,1 milissegundos), o loop fica mais rápido à medida que o número de iterações aumenta, embora o tempo total ainda seja alto. Isso vale para a criação de tamanhos diferentes de cadeias de espaço.
kmecpp

batida acima para solução bastante agradável, eu tê-lo usado na minha resposta aqui stackoverflow.com/questions/852665/...
maytham-ɯɐɥʇʎɐɯ

66

Hmm agora que penso nisso, talvez Arrays.fill:

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

Obviamente, suponho que o fillmétodo faça a mesma coisa que o seu código, portanto provavelmente terá o mesmo desempenho, mas pelo menos isso é menos linhas.


2
Depois de verificar a fonte, parece que isso realmente faz exatamente o que o OP postou: linha 806 de docjar.com/html/api/java/util/Arrays.java.html
Pops

2
@Lorde Torgamus A pergunta do OP foi editada? Porque na versão que eu vejo, ele está fazendo um loop no StringBuffer.append (), e a versão do Frustrated está fazendo um preenchimento (o que, obviamente, faz um loop na atribuição de caracteres para o array). Não é a mesma coisa.
CPerkins

@CPerkins, é justo, eu não estava claro. O que quero dizer é que os dois fazem uma inserção de caractere por caractere dentro de um loop for.
Pops

1
@ Lord Torgamus - concordou com isso. pena que o jvm não pode simplesmente fazer um memset. Preço que pagamos por caracteres largos.
CPerkins

2
@Pops, é importante notar que, se a Arrays.fill()função for usada consistentemente para fazer esse trabalho em todo o seu código e código de biblioteca (padrão e externo), será um bom candidato para a compilação de Hotspot e terá uma chance maior de ser encontrado no cache da CPU. As JVMs futuras podem atribuí-lo como uma função intrínseca . Rolar seus próprios corta fora de toda essa bondade desempenho ...
SusanW

65

Eu sugiro não escrever o loop manualmente. Você fará isso repetidamente durante o curso de sua carreira em programação. As pessoas que leem seu código - que inclui você - sempre precisam investir tempo, mesmo que sejam apenas alguns segundos, para digerir o significado do loop.

Em vez disso, reutilize uma das bibliotecas disponíveis, fornecendo código que é exatamente igualStringUtils.repeat ao Apache Commons Lang :

StringUtils.repeat(' ', length);

Dessa forma, você também não precisa se preocupar com desempenho, portanto, todos os detalhes sangrentos de StringBuilderotimizações do compilador etc. ficam ocultos. Se a função fosse lenta, seria um erro da biblioteca.

Com o Java 11 , fica ainda mais fácil:

" ".repeat(length);

5
Por outro lado, se StringUtils ainda não estiver sendo usado no projeto, adicionar mais uma dependência para uma tarefa tão simples pode ser um exagero.
Erich Kitzmueller

1
se o resultado for lento, você também poderá enviar sua própria correção para a função.
vai


13

Se você deseja apenas espaços, que tal:

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

o que resultará em abs (n) espaços;


6
Como é isso para a velocidade? Estou no formato de impressão é relativamente lento. Ele precisa analisar a string antes de poder criá-la, afinal.
C. Ross

11

desde o Java 11 :

" ".repeat(10);

desde o Java 8 :

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

Onde:

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

9

Desde o Java 11, você pode simplesmente usar String.repeat(count)para resolver seu problema.

Retorna uma string cujo valor é a concatenação dessa string repetida count vezes.

Se essa sequência estiver vazia ou countfor zero, a sequência vazia será retornada.

Então, em vez de um loop, seu código ficaria assim:

" ".repeat(length);

8

Eu acho que esse é o menor código possível, ele usa a classe Guava Joiner:

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


A menor linha de código, mas adicionar uma grande biblioteca apenas para essa tarefa simples, não faz sentido. Eu mesmo posso criar um JAR menor com um único método pubic String n(int n) { ... }que permitirá código "menos": n(10)mas, novamente, não faz sentido.
Isapir

@isapir Esta é uma grande resposta para as pessoas que já estão usando Goiaba
Nasch

1
@nasch Guava não fazia parte da questão. Mas de qualquer maneira, em 2018 não há realmente nenhuma razão para usar Joiner Guava quando você pode usar String.Join () que foi adicionado no Java 8. Ver stackoverflow.com/a/43011939/968244
isapir

@isapir Não, goiaba foi uma resposta. As respostas no StackOverflow têm um público-alvo mais amplo do que apenas a pessoa que faz a pergunta; portanto, é bom que algumas respostas não sejam as melhores para a pessoa que faz a pergunta. E o comentário sobre String.join () é ótimo, embora não tenha certeza se está disponível em todas as versões do Android, que é um uso proeminente do Java.
Nasch

7

Você pode usar a String.formatfunção padrão para gerar N espaços. Por exemplo:

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

Faz uma string com 5 espaços.

ou

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

Faz uma sequência de 15 barras de espaço.

Se você deseja que outro símbolo se repita, substitua espaços pelo símbolo desejado:

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

Resultado:

#######

6

Minha contribuição é baseada no algoritmo para exponenciação 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));
}

Testei o algoritmo contra duas outras abordagens:

  • Regular para loop usando String.concat()para concatenar string
  • Regular para loop usando um StringBuilder

Código de teste (concatenação usando um loop for e String.concat()fica muito lento n, então deixei de fora após a 5ª iteração).

/**
 * 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

Conclusão:

  • Para grandes n- use a abordagem recursiva
  • Para pequenos n- o loop for tem velocidade suficiente

4
Esta é uma implementação interessante. Infelizmente, contrariamente às suas conclusões, é muito ineficiente para grandes n. Suspeito que isso se deva às muitas alocações de memória que acontecem toda vez que você concatena seqüências de caracteres. Tente escrevê-lo como um invólucro em torno de um método recursivo que utiliza StringBuilder em vez de String. Aposto que você encontrará os resultados muito melhores.
precisa saber é o seguinte

3
Há muitas precauções que você precisa tomar ao fazer um micro-benchmarking como esse, e eu não acho que você esteja tomando nenhuma delas! As questões de desempenho dominantes em torno desse código poderiam ser facilmente se ele é compilado no Hotspot, quanto lixo ele cria etc. Aposto que todas essas ifdeclarações vão atrapalhar a previsão de ramificação da CPU. Isso realmente deve ser refeito usando JMH ( openjdk.java.net/projects/code-tools/jmh ), caso contrário, é um pouco inútil.
SusanW

Note-se que esta implementação tem O (n * log n) a complexidade, enquanto StringBuilder é O (n) :)
Leo Leontev


4

Considerando que temos:

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 (usando fluxo)

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)é equivalente aCollectors.joining()
PPartisan

2

RandomStringUtils tem uma provisão para criar uma string a partir de um determinado tamanho de entrada. Não posso comentar sobre a velocidade, mas é um forro.

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

cria uma saída

\ t \ t \ t \ t \ t

preferível se você não quiser ver \ 0 no seu código.



1

Na maioria dos casos, você só precisa de Strings até um determinado comprimento, digamos 100 espaços. Você pode preparar uma matriz de Strings em que o número do índice seja igual ao tamanho da string preenchida com espaço e procurar a string, se o comprimento necessário estiver dentro dos limites ou criá-lo sob demanda, se estiver fora do limite.



0

Apenas substitua seu StringBuffer por um StringBuilder . Difícil de superar isso.

Se o seu comprimento for um número grande, você poderá implementar um anexo automático mais eficiente (mas mais desajeitado), duplicando o comprimento em cada iteração:

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

Além disso, você pode tentar a Arrays.fill()abordagem ( resposta do FrustratedWithFormsDesigner ).


Você pode nomear algumas das variáveis ​​com mais de um caractere?
C. Ross

0

Você pode substituir StringBufferporStringBuilder (o último não está sincronizado, pode ser mais rápido em um aplicativo de thread único)

E você pode criar a StringBuilderinstância uma vez, em vez de criá-la sempre que precisar.

Algo assim:

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

  }

E use-o assim:

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

Se você mantiver sua createAvariável de instância, poderá economizar tempo criando instâncias.

Isso não é seguro para threads, se você tiver vários threads, cada thread deverá ter sua própria cópia.


0

Para obter um bom desempenho, combine as respostas do aznilamir e do 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 o tamanho de BLANKSacordo com suas necessidades. Minha BLANKSstring específica tem cerca de 200 caracteres.


0

Tenha um método como este. Isso acrescenta espaços necessários no final do dado Stringpara dar um dado Stringao comprimento de comprimento específico.

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

Deseja que a String seja de tamanho fixo, para que você forme ou trunque, para tabular dados ...

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 referência aqui .


0

Isso funcionou para mim sem usar nenhuma biblioteca externa no Java 8

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

E a saída é

testtesttest

0

int c = 10; Espaços de string = String.format ("%" + c + "c", ''); Isto irá resolver o seu problema.


-1

Um método simples como abaixo também pode ser usado

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

Isso é subsidiariamente mais lento.
SLaks

Você pode usar StringBuffer em vez de concatenação de strings, caso as strings com as quais você está lidando sejam de tamanho grande. Que terá impacto sobre a velocidade consideravelmente
Yashpal Singla

-2

que tal agora?

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

Edição: Eu escrevi um código simples para testar o conceito e aqui o que eu encontrei.

Método 1: adicionando espaço único em um loop:

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

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

    return sb.toString();
  }

Método 2: anexar 100 espaços e loop e, em seguida, substring:

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

O resultado que obtive criando 12.345.678 espaços:

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

e para 10.000.000 de espaços:

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

combinar alocação direta e iteração sempre leva menos tempo, em média 60ms menos ao criar grandes espaços. Para tamanhos menores, ambos os resultados são insignificantes.

Mas, por favor, continue a comentar :-)


3
@ aznilamir: Hm, como você fará por 10 mil espaços?
Jayan

A idéia é combinar loop e alocação direta de 100 espaços. Aqui está os trechos de código:
aznilamir

Por que você usa vários anexos para adicionar 100 caracteres? Por que não um acréscimo de 100 caracteres?
Nycynik 17/08/16

-3

Não conheço nenhum método interno para o que você está perguntando. No entanto, para um pequeno comprimento fixo como 10, seu método deve ser bastante rápido.


Se fosse um pequeno comprimento fixo como 10.
C. Ross
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.