如何在Java中填充字符串?

505

有没有一种简单的方法在Java中填充字符串?

这似乎是一些类似于StringUtil的API应该有的东西,但我找不到任何可以实现这一点的内容。

33个回答

7

我知道这个帖子有点老了,原始问题是要一个简单的解决方案,但如果需要速度真的很快,你应该使用字符数组。

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个新字符串。

Apache的解决方案可以通过使用目标大小初始化sb来进行改进,因此替换如下:

StringBuffer padded = new StringBuffer(str); 

使用

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

这将防止sb的内部缓冲区增长。


1
如果StringBuffer不能同时被多个线程访问(在这种情况下是真的),则应使用StringBuilder(在JDK1.5+中)以避免同步开销。 - glen3b

6

我花了一点时间才弄清楚这个。 真正的关键是阅读Formatter文档。

// 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", digest); 就能得到完全相同的结果,而不必进行无用的 replace() 操作和使用 $ 访问特定变量(毕竟只有一个变量)。 - ArtOfWarfare
@ArtOfWarfare 说得好。有人在另一个问题中最初要求填充十六进制值,我看到我有一个链接到格式化程序文档。这是为了完整性而复杂的。 - Nthalk

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

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
这是线程安全的,除了不安全的发布(将字段作为常规操作设为final)。我认为通过在+之前执行子字符串(奇怪的是应该替换为concat)可以提高性能。 - Tom Hawtin - tackline

3

所有的字符串操作通常需要非常高效 - 特别是当您处理大量数据时。我希望拥有快速且灵活的东西,类似于您将在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()方法可以将字符串转换为字符数组,然后使用new String((char[])result)方法可以将字符数组转换回字符串。这样做的原因是,如果您要对多个操作进行处理,可以在char[]类型上执行所有操作,而不必在不同格式之间不断进行转换 - 实际上,String类型在幕后是以char[]类型存储的。如果这些操作都包含在String类本身中,它们的速度和内存效率将提高一倍。

这确实看起来是最有效的方式。 - David Lilljegren
public static String lpad(String pString, int pTotalLength, char pPad) { return new String(lpad(pString.toCharArray(), pTotalLength, pPad)); }公共静态字符串lpad(字符串pString,int pTotalLength,char pPad){return new String(lpad(pString.toCharArray(),pTotalLength,pPad));} - samwyse

3

@ck@Marlon Tarak的答案是唯一使用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
你可以使用getChars方法,让String直接将其内容复制到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

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
请使用这个函数。
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


使用递归意味着你容易遭受栈溢出,并且往往效率低下(重复的 ch + word 加上函数调用开销)。 - ggorlen

2

如果您需要在将字符串连接到另一个字符串之前添加左/右填充(或前缀/后缀字符串或空格),并且不想测试长度或任何if条件,则可以使用以下方法:

与所选答案相同,我更喜欢使用Apache Commons的StringUtils,但是使用以下方式:

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

解释:

  • myString:我输入的字符串,可以为 null
  • StringUtils.leftPad(myString, 1):如果字符串为 null,则此语句也将返回 null
  • 然后使用 defaultString 给空字符串以避免连接 null

2

这个有效:

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

这段代码会将您的字符串XXX填充到9个字符长度,并用空格进行填充。之后所有的空格都将被替换为0。您可以自定义所需的填充字符和替换字符。


你应该调用static方法,而不是滥用空字符串,调用方式为String.format(…)。在源代码中节省四个字符肯定不值得失去可读性。 - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接