Como posso preencher uma String em Java?

432

Existe alguma maneira fácil de preencher Strings em Java?

Parece algo que deveria estar em alguma API do tipo StringUtil, mas não consigo encontrar nada que faça isso.

pvgoddijn
fonte
Sobre a questão da função apache versus o formatador de strings, há poucas dúvidas de que a função apache é mais clara e fácil de ler. Envolvendo o formatador em nomes de funções não é o ideal.
Terra Caines

Respostas:

189

Apache StringUtilstem vários métodos: leftPad, rightPad, centere repeat.

Mas observe que - como outros já mencionaram e demonstraram nesta resposta - String.format()e as Formatterclasses no JDK são melhores opções. Use-os sobre o código comum.

GaryF
fonte
91
java.util.Formatter (e String.format ()) faz isso. Sempre prefira o JDK a uma biblioteca externa se a versão do JDK fizer o trabalho (o que faz).
Cletus
6
Por várias razões, agora eu preferiria o Goiaba ao Apache Commons; esta resposta mostra como fazê-lo na goiaba .
31812 Jonik
1
@ Jonik, você gostaria de listar algumas de suas razões? As APIs têm a mesma aparência.
Glen3b
3
@ glen3b: Para um utilitário individual, como esses auxiliares de preenchimento de cordas, realmente não faz diferença qual lib usar. Dito isto, o Guava é, em geral, uma lib mais moderna, mais limpa e melhor documentada do que suas contrapartes em vários projetos do Apache Commons (Commons Lang, Commons Collections, Commons IO, etc). Também é construído por caras realmente inteligentes (Kevin Bourrillion et al), muitos dos quais são ativos na SO . Eu mesmo acabei substituindo as várias bibliotecas do Apache Commons por apenas Guava anos atrás, e não me arrependo.
Jonik
3
@ glen3b: Algumas boas leituras adicionais nesta questão .
Jonik
635

Desde o Java 1.5, String.format()pode ser usado para preencher esquerda / direita uma determinada string.

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

E a saída é:

Howto               *
               Howto*
RealHowTo
fonte
39
E se você precisar lpad com outros caracteres (não espaços)? Ainda é possível com o String.format? Eu não sou capaz de fazê-lo funcionar ...
Guido
6
AFAIK String.format () não pode fazer isso, mas não é muito difícil de código-lo, ver rgagnon.com/javadetails/java-0448.html (2ª exemplo)
RealHowTo
61
@ Nullw0rm, se você está se referindo a rgagnon.com, estar ciente de que RealHowTo é o autor de rgagnon.com também, então ele seria creditando-se ...
Colin Pickard
3
pelo menos na minha JVM, o "#" não funciona, o "-" está bom. (Apenas apague o #). Isso pode ser consistente com a documentação do formatador, não sei; ele diz "'#' '\ u0023' Requer que a saída use um formulário alternativo. A definição do formulário é especificada pela conversão."
gatoatigrado
6
Obrigado pela resposta incrível. Mas tenho uma dúvida: para que serve 1$? @leo fez uma resposta muito semelhante que não usa 1$e aparentemente tem o mesmo efeito. Isso faz diferença?
Fabrício Matté 8/03/13
257

Preenchimento com 10 caracteres:

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

resultado:

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

Exiba '*' para caracteres de senha:

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

A saída tem o mesmo comprimento que a string da senha:

  secret123
  *********
leo
fonte
50
Contanto que todos nós nos lembramos para não passar uma cadeia com espaços ...: D
leviathanbadger
4
Estou com @ aboveyou00 - esta é uma solução horrenda para strings com espaços, incluindo o exemplo fornecido por leo. Uma solução para preencher uma string à esquerda ou à direita não deve alterar a string de entrada como aparece na saída, a menos que o preenchimento original da string de entrada faça com que ela exceda o comprimento de preenchimento especificado.
Brian Warshaw
3
Reconheça o problema de espaço. .replace(' ', '*')teve a intenção de mostrar o efeito do preenchimento. A expressão oculta da senha não tem esse problema de qualquer maneira ... Para obter uma resposta melhor sobre como personalizar a cadeia de preenchimento esquerda e direita usando o recurso Java nativo, consulte minha outra resposta.
leo
Se a string contém apenas espaços simples e você quer pad com personagens diferentes, você pode usar regex substituir com olhar para trás / frente: String.format("%30s", "pad left").replaceAll("(?<=( |^)) ", "*")ouString.format("%-30s", "pad right").replaceAll(" (?=( |$))", "*")
Jaroslaw Pawlak
88

Na Goiaba , isso é fácil:

Strings.padStart("string", 10, ' ');
Strings.padEnd("string", 10, ' ');
Garrett Hall
fonte
33

Algo simples:

O valor deve ser uma sequência. converta-o em string, se não estiver. Curtir "" + 123ouInteger.toString(123)

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

Início da cadeia de caracteres do índice de caracteres de comprimento do valor até o comprimento final do preenchimento:

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

// now padded is "00000123"

Mais preciso

almofada direita:

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

// now padded is "123DEFGH"

almofada esquerda:

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

// now padded is "ABCDE123"
Shimon Doodkin
fonte
24

Dê uma olhada org.apache.commons.lang.StringUtils#rightPad(String str, int size, char padChar).

Mas o algoritmo é muito simples (pad até o tamanho dos caracteres):

public String pad(String str, int size, char padChar)
{
  StringBuffer padded = new StringBuffer(str);
  while (padded.length() < size)
  {
    padded.append(padChar);
  }
  return padded.toString();
}
Arne Burmeister
fonte
11
Observe que no Java 1.5 vale a pena usar o StringBuilder em vez do StringBuffer.
Jon Skeet
21

Além do Apache Commons, veja também o String.formatque deve ser capaz de cuidar do preenchimento simples (por exemplo, com espaços).

Variável miserável
fonte
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...
Eduardo
fonte
4
Preste atenção: você inverte os nomes das funções; se você executá-lo, verá.
azulado
mais se o str original contém espaços, em seguida, isso não funciona
Steven Shaw
@StevenShaw Se não me engano, a substituição não tem como alvo o original str, então isso está correto.
Mafu
3
Por convenção, você não deve usar letras maiúsculas para nomes de funções.
principal-ideal-domain
Existe uma condicional ausente no retorno da string como é quando (length - str.length())é 0? O formatador lança a FormatFlagsConversionMismatchExceptionquando %0sé a string de formato.
Devin Walters
7

Demorei um pouco para descobrir. A chave real é ler a documentação do Formatador.

// 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);
Nthalk
fonte
Por que tornar o fim tão complicado? Você poderia ter feito String hex = String.format ("% 032x", resumo); e teve os mesmos resultados, só que sem a desnecessária replace () e ter que usar o $ para variáveis de acesso específicos (só há um, afinal.)
ArtOfWarfare
@ArtOfWarfare fair point. Alguém originalmente pediu preenchimento de valores hexadecimais em outra pergunta. Vi que tinha um link para a documentação do formatador. É complicado para ser completo.
Nthalk
6

Eu sei que este tópico é meio antigo e a pergunta original era para uma solução fácil, mas se deveria ser realmente rápido, você deve usar uma matriz de caracteres.

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

a solução do formatador não é ótima. apenas construir a string de formato cria 2 novas strings.

A solução do apache pode ser aprimorada inicializando o sb com o tamanho do destino, substituindo-o abaixo

StringBuffer padded = new StringBuffer(str); 

com

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

impediria o crescimento do buffer interno do sb.

ck.
fonte
Se StringBuffernão puder ser acessado por vários encadeamentos de uma só vez (o que neste caso é verdadeiro), você deverá usar um StringBuilder(no JDK1.5 +) para evitar a sobrecarga da sincronização.
glen3b
5

Aqui está outra maneira de colocar à direita:

// 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-------";
fawsha1
fonte
5

Desde o Java 11, String.repeat (int) pode ser usado para preencher esquerda / direita uma determinada string.

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

Resultado:

*****apple
apple*****
Eko Setiawan
fonte
1
Melhor resposta para java 11!
Nagy Attila
4

Você pode reduzir a sobrecarga por chamada mantendo os dados de preenchimento, em vez de recriá-los sempre:

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

}

Como alternativa, você pode tornar o comprimento do resultado um parâmetro para o pad(...)método Nesse caso, faça o ajuste do preenchimento oculto nesse método em vez de no construtor.

(Dica: para obter crédito extra, torne-o seguro para threads! ;-)

joel.neely
fonte
1
Isso é seguro para threads, exceto para publicação não segura (torne seus campos finais, como é óbvio). Eu acho que o desempenho pode ser melhorado fazendo uma substring antes do + que deve ser substituído por concat (estranhamente).
Tom Hawtin - defina dec
3

Encontrei isso no Dzone

Almofada com zeros:

String.format("|%020d|", 93); // prints: |00000000000000000093|
OJVM
fonte
Essa deve ser a resposta, simples e concisa, sem necessidade de instalar bibliotecas externas.
Wong Jia Hau
2

você pode usar os métodos incorporados StringBuilder append () e insert (), para preenchimento de comprimentos variáveis ​​de string:

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

Por exemplo:

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());
ef_oren
fonte
2

Isso funciona:

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

Ele preencherá sua String XXX até 9 caracteres com um espaço em branco. Depois disso, todos os espaços em branco serão substituídos por um 0. Você pode alterar o espaço em branco e o 0 para o que quiser ...

Sebastian S.
fonte
Você deve invocar o staticmétodo para String.format(…)não abusar de uma sequência vazia. Salvar quatro caracteres no código fonte certamente não vale a perda de legibilidade.
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 "";
}
Marlon Tarax
fonte
2

Deixe-me deixar uma resposta para alguns casos em que você precisa fornecer preenchimento esquerdo / direito (ou sequência ou espaços de prefixo / sufixo) antes de concatenar para outra sequência e não desejar testar o comprimento ou qualquer condição if.

O mesmo que a resposta selecionada, eu preferiria o StringUtilsApache Commons, mas usando desta maneira:

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

Explicar:

  • myString: a string que eu insiro, pode ser nula
  • StringUtils.leftPad(myString, 1): se a cadeia for nula, esta instrução retornará nulo também
  • use defaultStringpara dar uma string vazia para evitar concatenar null
Osify
fonte
2

As respostas @ck e @Marlon Tarak são as únicas a usar a char[], o que para aplicativos que têm várias chamadas para métodos de preenchimento por segundo é a melhor abordagem. No entanto, eles não tiram vantagem de nenhuma otimização de manipulação de array e são um pouco substituídos pelo meu gosto; isso pode ser feito sem loops .

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étodo de teste simples:

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

Saídas:

012345678901234567890123456789
cats                          
                          cats
                cats
cats$$$$$$$$$$$$$$$$$$$$$$$$$$
too long for your own good, buddy 
ndm13
fonte
1
Você pode usar getCharspara permitir que o Stringconteúdo seja copiado diretamente na outmatriz, em vez de chamar source.toCharArray(), seguido por System.arraycopy. Eu consideraria até simplificar a implementação 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);; embora isso pareça fillmais trabalhoso, na verdade permite que a JVM elimine o preenchimento zero padrão.
Holger
1

java.util.Formatterfará preenchimento esquerdo e direito. Não há necessidade de dependências estranhas de terceiros (você gostaria de adicioná-las para algo tão trivial).

[Deixei de fora os detalhes e criei este post como 'wiki da comunidade', pois não é algo que eu precise.]

Tom Hawtin - linha de orientação
fonte
4
Discordo. Em qualquer projeto Java maior, você normalmente realiza tanta manipulação de String, que vale a pena usar o Apache Commons Lang para aumentar a legibilidade e evitar erros. Todos vocês conhecem códigos como someString.subString (someString.indexOf (startCharacter), someString.lastIndexOf (endCharacter)), que pode ser facilmente evitado com StringUtils.
Bananeweizen
1

Toda operação de cadeia geralmente precisa ser muito eficiente - especialmente se você estiver trabalhando com grandes conjuntos de dados. Eu queria algo rápido e flexível, semelhante ao que você obterá no comando plsql pad. Além disso, não quero incluir uma enorme lib por apenas uma pequena coisa. Com essas considerações, nenhuma dessas soluções foi satisfatória. Estas são as soluções que eu encontrei, que tiveram os melhores resultados de benchmarking, se alguém puder melhorar, adicione seu comentário.

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;
    }
}
  • note que é chamado com String.toCharArray () e o resultado pode ser convertido em String com o novo resultado de String ((char [])). A razão para isso é que, se você aplicar várias operações, poderá fazê-las todas em char [] e não continuar convertendo entre formatos - nos bastidores, String é armazenada como char []. Se essas operações fossem incluídas na própria classe String, seria duas vezes mais eficiente - velocidade e memória.
EarlB
fonte
Este fato parece a forma mais eficiente
David Lilljegren
1

Use esta função.

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

Como usar?

leftPadding(month, 2, '0');

saída: 01 02 03 04 .. 11 12

Samet ÖZTOPRAK
fonte
1

Muitas pessoas têm algumas técnicas muito interessantes, mas eu gosto de simplificar, então eu vou com isso:

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();
}
Aelphaeis
fonte
2
Isto é muito ineficiente, você deve usar um StringBuilder
wkarl
Como você já sabe o comprimento, você deve pedir ao StringBuilder para alocar tanto espaço quando o instanciar.
Ariel #
@ Ariel interessante que você mencionou isso, porque eu estava apenas conversando com alguém sobre isso hoje, lol.
Aelphaeis
0

Uma solução simples sem qualquer API será a seguinte:

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();
}
Shashank Shekhar
fonte
0

Oneliners de Java, nenhuma biblioteca sofisticada.

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

Almofada à esquerda, não limite

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

Almofada direita, não limite

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

Almofada esquerda, limite do comprimento da almofada

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

Almofada direita, limite ao comprimento da almofada

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

Que tal usar recursão? A solução fornecida abaixo é compatível com todas as versões do JDK e sem a necessidade de bibliotecas externas :)

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

NOTA : Esta solução acrescentará o preenchimento. Com um pequeno ajuste, você pode prefixar o valor do preenchimento.

Saikat
fonte
0

Aqui está uma versão paralela para aqueles que têm seqüências muito longas :-)

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));
David Lilljegren
fonte
0

Exemplos de preenchimento na goiaba:

Exemplos de preenchimento no Apache Commons:

Exemplos de preenchimento no JDK:

APISonar
fonte
-1

Uma solução simples seria:

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

Como é isso

A string é "olá" e o preenchimento obrigatório é 15 com o pad esquerdo "0"

String ax="Hello";
while(ax.length() < 15) ax="0"+ax;
Satwant
fonte
10
este gera até 15 novas strings.
claj
@claj Sim, mas isso .
Ruffin