如何在Java中填充字符串?


431

有一些简单的方法可以在Java中填充字符串吗?

似乎应该在类似StringUtil的API中使用某些东西,但是我找不到执行此操作的任何东西。


在apache函数与字符串格式化程序的问题上,毫无疑问apache函数更加清晰易读。将格式化程序包装在函数名称中并不理想。
Terra Caines

Answers:


189

阿帕奇StringUtils有几种方法:leftPadrightPadcenterrepeat

但请注意-如其他人所说的,并证明了这个答案 - String.format()FormatterJDK中的类是更好的选择。在公共代码上使用它们。


91
java.util.Formatter(和String.format())执行此操作。如果JDK版本完成了这项工作,则总是偏爱JDK而不是外部库。
cletus

6
由于多种原因,我现在更希望使用番石榴而不是Apache Commons。这个答案说明了如何在Guava中做到这一点
约尼克(Jonik)2012年

1
@Jonik您是否愿意列出一些原因?这些API看起来几乎一样。
glen3b 2014年

3
@ glen3b:对于单个实用程序,例如这些字符串填充助手,使用哪个库实际上没有区别。也就是说,与各种Apache Commons项目(Common Lang,Commons Collections,Commons IO等)中的Guava相比,Guava总体上来说是一个更现代,更干净,文档更完善的lib。它也是由非常聪明的人(Kevin Bourrillion等人)构建的,其中许多人都活跃在SO上。我本人最后几年才用Guava替换了各种Apache Commons库,对此我并不后悔。
尼克

3
@ glen3b:在这个问题上有一些不错的进一步阅读
尼克

634

从Java 1.5开始,String.format()可用于左/右填充给定的字符串。

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

输出为:

Howto               *
               Howto*

39
如果需要与其他字符(不是空格)组合在一起怎么办?String.format仍然可行吗?我无法使其工作...
Guido,2009年

6
AFAIK String.format()不能做到这一点,但是对其进行编码并不是很困难,请参阅rgagnon.com/javadetails/java-0448.html(第二个示例)
RealHowTo 2009年

61
@ Nullw0rm,如果您指的是rgagnon.com,请注意RealHowTo也是rgagnon.com的作者,因此,他也将自己归功于自己
Colin Pickard 2010年

3
至少在我的JVM上,“#”不起作用,“-”很好。(只需删除#)。这可能与格式化程序文档一致,我不知道。它说:“'#''\ u0023'要求输出使用替代格式。该格式的定义由转换指定。”
gatoatigrado 2011年

6
感谢您的答复。我对此有疑问,这是1$为了什么?@leo给出了一个非常相似的答案,没有使用1$,并且显然具有相同的效果。这有什么不同吗?
法布里西奥磨砂

257

填充10个字符:

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

输出:

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

在密码字符上显示“ *”:

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

输出的长度与密码字符串的长度相同:

  secret123
  *********

50
只要我们都记得不要在带空格的字符串中传递...:D
leviathanbadger 2013年

4
我在@ aboveyou00上使用-这是带空格的字符串的可怕解决方案,包括leo提供的示例。一种用于在左侧或右侧填充字符串的解决方案不应更改输入字符串,因为它不会出现在输出中,除非输入字符串的原始填充导致其超过指定的填充长度。
Brian Warshaw 2015年

3
确认空间问题。.replace(' ', '*')而是旨在显示填充效果。无论如何,密码隐藏表达式都不存在此问题...有关使用本机Java功能自定义左右填充字符串的更好答案,请参见我的其他答案。
leo

如果字符串仅包含单个空格,并且您希望使用不同的字符进行填充,则可以使用正则表达式替换为“ look back / ahead”:String.format("%30s", "pad left").replaceAll("(?<=( |^)) ", "*")String.format("%-30s", "pad right").replaceAll(" (?=( |$))", "*")
Jaroslaw Pawlak,


33

简单的事情:

该值应该是一个字符串。如果不是,则将其转换为字符串。喜欢"" + 123Integer.toString(123)

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

子字符串从值长度char索引开始,直到填充的结束长度:

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

// now padded is "00000123"

更精确

向右垫:

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

// now padded is "123DEFGH"

左垫:

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

// now padded is "ABCDE123"

24

看一看org.apache.commons.lang.StringUtils#rightPad(String str, int size, char padChar)

但是算法非常简单(按大小字符填充):

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
请注意,从Java 1.5开始,值得使用StringBuilder代替StringBuffer。
乔恩·斯基特

21

除了Apache Commons外,还String.format应该了解哪些应该能够进行简单的填充(例如,使用空格)。


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
注意:您倒置了函数名称;如果您运行它,将会看到。
蓝色2012年

另外,如果原始str包含空格,那么这将不起作用
Steven Shaw

@StevenShaw如果我没记错的话,替换对象不是原始对象str,所以这是正确的。
mafu 2014年

3
按照惯例,函数名称不应使用大写字母。
主理想域

是否有作为时返回字符串缺少的条件(length - str.length())0?格式化程序将在格式字符串中抛出一个FormatFlagsConversionMismatchExceptionwhen %0s
德文·沃尔特斯

7

这花了我一段时间才弄清楚。真正的关键是阅读格式化程序文档。

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

为什么使结果如此复杂?您可能刚完成String hex = String.format(“%032x”,摘要); 并有同样的结果,只是没有不必要的更换()和不必使用$来访问特定变量(只有一个有,毕竟。)
ArtOfWarfare

@ArtOfWarfare公平点。最初有人在另一个问题中要求填充十六进制值,我看到我有一个指向格式化程序文档的链接。完整性很复杂。
Nthalk

6

我知道这个线程有点陈旧,最初的问题是一个简单的解决方案,但是如果它真的很快,则应该使用char数组。

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

格式化程序解决方案不是最佳的。仅构建格式字符串会创建2个新字符串。

可以通过将sb初始化为目标大小来改进apache的解决方案,因此请在下面替换

StringBuffer padded = new StringBuffer(str); 

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

会阻止某人的内部缓冲区增长。


如果StringBuffer无法一次被多个线程访问(在这种情况下为true),则应使用StringBuilder(在JDK1.5 +中)以避免同步的开销。
glen3b 2014年

5

这是向右滑动的另一种方法:

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

从Java 11开始,String.repeat(int)可用于左/右填充给定的字符串。

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

输出:

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

1
Java 11的最佳答案!
Nagy Attila

4

您可以通过保留填充数据来减少每次呼叫的开销,而不是每次都重新构建它:

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

}

或者,您可以将结果长度作为pad(...)方法的参数。在这种情况下,请在该方法中而不是在构造函数中调整隐藏的填充。

(提示:要获得额外的信誉,请使其成为线程安全的!;-)


1
那是线程安全的,除了不安全的发布(当然,请使字段最终确定)。我认为可以通过在+之前添加一个子字符串来提高性能,该子字符串应由concat替换(足够奇怪)。
Tom Hawtin-大头钉

3

Dzone上找到了这个

用零填充:

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

这应该是答案,简单明了,无需安装外部库。

2

您可以使用内置的StringBuilder append()和insert()方法来填充可变字符串长度:

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

例如:

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

这有效:

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

它将用空格填充您的字符串XXX(最多9个字符)。之后,所有空白都将替换为0。您可以将空白和0更改为所需的任何值...


您应将static方法调用为,String.format(…)而不是滥用空字符串。在源代码中保存四个字符肯定不值得牺牲可读性。
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

在某些情况下,让我留下一个答案:在连接到另一个字符串之前,您需要给左/右填充(或前缀/后缀字符串或空格),并且您不想测试长度或任何if条件。

与所选答案相同,我希望使用StringUtilsApache Commons的,但使用这种方式:

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

说明:

  • myString:我输入的字符串,可以为null
  • StringUtils.leftPad(myString, 1):如果string为null,则该语句也将返回null
  • 然后使用defaultString给出空字符串以防止串联null

2

@ck@Marlon Tarak的答案是唯一使用a的答案char[],对于每秒多次调用填充方法的应用程序来说,这是最好的方法。但是,它们没有利用任何数组操作优化,因此就我的口味而言有些覆盖。这完全可以做到没有循环

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

简单的测试方法:

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

输出:

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

1
您可以使用getCharsString复制其内容直接进入out阵列,而不是调用source.toCharArray(),其次是System.arraycopy。我什至考虑简化实现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);;尽管这看起来fill会做更多的工作,但实际上它允许JVM消除默认的零填充。
Holger

1

java.util.Formatter将进行左右填充。不需要奇怪的第三方依赖关系(您是否想为琐碎的事情添加它们)。

[我省略了细节,并把这篇文章设为“社区Wiki”,因为这不是我所需要的。]


4
我不同意。在任何较大的Java项目中,您通常都会进行大量的String操作,因此使用Apache Commons Lang值得提高可读性和避免错误。大家都知道类似someString.subString(someString.indexOf(startCharacter),someString.lastIndexOf(endCharacter))之类的代码,可以使用StringUtils轻松避免。
Bananeweizen 2011年

1

通常,所有字符串操作都必须非常高效 -尤其是在处理大量数据时。我想要一种快速灵活的功能,类似于在plsql pad命令中将获得的功能。另外,我不想为一个小东西就包含一个巨大的库。考虑到这些考虑,这些解决方案都不令人满意。这是我想出的解决方案,具有最佳基准测试结果,如果有人可以改进它,请添加您的评论。

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;
    }
}
  • 请注意,它使用String.toCharArray()调用,并且可以使用新的String((char [])result)将结果转换为String。这样做的原因是,如果您应用多个操作,则可以对char []进行全部操作,而不必继续在格式之间进行转换-在后台,String存储为char []。如果将这些操作包含在String类本身中,那么它的效率将提高一倍-在速度和内存方面。

这确实看起来是最有效的方法
David Lilljegren

1

使用此功能。

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

如何使用?

leftPadding(month, 2, '0');

输出:01 02 03 04 .. 11 12


1

很多人都有一些非常有趣的技术,但是我想保持简单,所以我继续:

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
这效率很低,您应该使用StringBuilder
wkarl

由于您已经知道长度,因此应在实例化时告诉StringBuilder分配足够的空间。
艾丽尔(Ariel)

@Ariel有趣的是,您提到那是因为今天我只是在和其他人聊天。
Aelphaeis

0

没有任何API的简单解决方案如下:

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

Java oneliners,没有精美的库。

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

左移垫板,不限

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

向右垫,不要限制

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

左垫,限制垫长度

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

垫右,限制垫长度

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

0

如何使用递归?下面给出的解决方案与所有JDK版本兼容,并且不需要外部库:)

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

注意:此解决方案将添加填充,只需稍作调整即可为填充值添加前缀。


0

这是针对那些字符串很长的人的并行版本:-)

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

一个简单的解决方案是:

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

-1

这怎么样

字符串为“ hello”,所需填充为15,左侧填充为“ 0”

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

10
这将产生多达15个新字符串。
claj 2014年

@claj是的,但是这个
鲁芬
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.