如何使用String.format居中一个字符串?

25
public class Divers {
  public static void main(String args[]){

     String format = "|%1$-10s|%2$-10s|%3$-20s|\n";
     System.out.format(format, "FirstName", "Init.", "LastName");
     System.out.format(format, "Real", "", "Gagnon");
     System.out.format(format, "John", "D", "Doe");

     String ex[] = { "John", "F.", "Kennedy" };

     System.out.format(String.format(format, (Object[])ex));
  }
}

输出:

|FirstName |Init.     |LastName            |
|Real      |          |Gagnon              |
|John      |D         |Doe                 |
|John      |F.        |Kennedy             |

我希望输出居中。如果不使用' - '标志,输出将被右对齐。

我在API中没有找到居中文本的标志。

这篇文章提供了一些格式方面的信息,但没有关于居中对齐的内容。


输出实际上是一个表格,所以由于某种原因,问题无法正确显示表格。 - rana
3
请参考 StringUtils https://dev59.com/b03Sa4cB1Zd3GeqPu2d- 或者 http://www.java2s.com/Code/Java/Data-Type/CentersaStringinalargerStringofsizesizeusingthespacecharacter.htm 以了解如何使用 printf 函数和变量宽度来居中字符串输出,同时保持原意不变。 - ecle
@eee 是标准库中的 StringUtils 吗? - rana
1
StringUtils 库来自 Apache(Apache 许可证)[http://commons.apache.org/lang/]。 - ecle
1
@eee 非常感谢。有没有办法使用标准库来完成这个操作? - rana
如果您查看第二个链接,您可以使用标准库 :) - ecle
9个回答

26

我匆忙地弄了这个。现在你可以在String.format中使用StringUtils.center(String s, int size)

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class TestCenter {
    @Test
    public void centersString() {
        assertThat(StringUtils.center(null, 0), equalTo(null));
        assertThat(StringUtils.center("foo", 3), is("foo"));
        assertThat(StringUtils.center("foo", -1), is("foo"));
        assertThat(StringUtils.center("moon", 10), is("   moon   "));
        assertThat(StringUtils.center("phone", 14, '*'), is("****phone*****"));
        assertThat(StringUtils.center("India", 6, '-'), is("India-"));
        assertThat(StringUtils.center("Eclipse IDE", 21, '*'), is("*****Eclipse IDE*****"));
    }

    @Test
    public void worksWithFormat() {
        String format = "|%1$-10s|%2$-10s|%3$-20s|\n";
        assertThat(String.format(format, StringUtils.center("FirstName", 10), StringUtils.center("Init.", 10), StringUtils.center("LastName", 20)),
                is("|FirstName |  Init.   |      LastName      |\n"));
    }
}

class StringUtils {

    public static String center(String s, int size) {
        return center(s, size, ' ');
    }

    public static String center(String s, int size, char pad) {
        if (s == null || size <= s.length())
            return s;

        StringBuilder sb = new StringBuilder(size);
        for (int i = 0; i < (size - s.length()) / 2; i++) {
            sb.append(pad);
        }
        sb.append(s);
        while (sb.length() < size) {
            sb.append(pad);
        }
        return sb.toString();
    }
}

1
我会坚持使用Apache Commons Lang中的StringUtils,因为它很容易通过Maven进行集成。 - rana
pad参数是String类型,但如果它的长度超过1个字符,该方法将无法正常工作。这个测试将失败assertEquals("01foo01", StringUtils.center("foo", 6, "0123"));。应该使用char类型。我会修复它。 - Oliv

18
public static String center(String text, int len){
    String out = String.format("%"+len+"s%s%"+len+"s", "",text,"");
    float mid = (out.length()/2);
    float start = mid - (len/2);
    float end = start + len; 
    return out.substring((int)start, (int)end);
}

public static void main(String[] args) throws Exception{
    // Test
    String s = "abcdefghijklmnopqrstuvwxyz";
    for (int i = 1; i < 200;i++){
        for (int j = 1; j < s.length();j++){
            //center(s.substring(0, j),i);
            System.out.println(center(s.substring(0, j),i));
        }
    }
}

4
好的回答!你可能想考虑把方法名改成小写,大写让它看起来像一个类而不是一个方法。 - papezjustin

15

将在https://www.leveluplunch.com/java/examples/center-justify-string/找到的代码转换为方便、简短的单行函数:

public static String centerString (int width, String s) {
    return String.format("%-" + width  + "s", String.format("%" + (s.length() + (width - s.length()) / 2) + "s", s));
}

使用方法:

public static void main(String[] args){
    String out = centerString(10, "afgb");
    System.out.println(out); //Prints "   afgb   "
}

我认为这是一个非常好的解决方案,值得一提。


很棒的解决方案!你能详细解释一下它是如何工作的吗? - Genhis

10

以下是使用Apache Commons Lang StringUtils的答案。

请注意,您必须将jar文件添加到构建路径中。如果您正在使用Maven,请确保在依赖项中添加commons lang。

import org.apache.commons.lang.StringUtils;
public class Divers {
  public static void main(String args[]){

    String format = "|%1$-10s|%2$-10s|%3$-20s|\n";
    System.out.format(format, "FirstName", "Init.", "LastName");
    System.out.format(format,StringUtils.center("Real",10),StringUtils.center("",10),StringUtils.center("Gagnon",20);

    System.out.format(String.format(format, (Object[])ex));
  }
}

1
这个答案更合适,因为使用了一个众所周知的库来实现此目的。 - Paulo Oliveira
1
同意 @PauloOliveira - Trevor Brown

7
int spaceSize = n - s.length();
int prefixSize = spaceSize / 2;
int suffixSize = (spaceSize + 1) / 2

"一行代码"自Java 11以来

return n > s.length()
     ? " ".repeat(prefixSize) + s + " ".repeat(suffixSize)
     : s;

将上述变量内联到一个返回语句中,我们可以得到:
``` return n > s.length() ? " ".repeat((n - s.length()) / 2) + s + " ".repeat((n - s.length() + 1) / 2) : s; ```
自 Java 8 开始,Java 没有 `" ".repeat(10)` 方法。所以,
  • just replace the " ".repeat(10) with Java 8 analog. See https://dev59.com/5XE85IYBdhLWcg3wYSZk#57514604, and

  • use the same (as Java 11 ☝️) alg:

      int spaceSize = n - s.length();
      int prefixSize = spaceSize / 2;
      int suffixSize = (spaceSize + 1) / 2
      return n > s.length()
           ? space(prefixSize) + s + space(suffixSize)
           : s;
    
    
    private String space(int spaceSize) {
      return generate(() -> " ").limit(spaceSize).collect(joining());
    }
    

3
我在尝试Mertuarez上面的精妙答案时,决定发布我的版本。
public class CenterString {

    public static String center(String text, int len){
        if (len <= text.length())
            return text.substring(0, len);
        int before = (len - text.length())/2;
        if (before == 0)
            return String.format("%-" + len + "s", text);
        int rest = len - before;
        return String.format("%" + before + "s%-" + rest + "s", "", text);  
    }

    // Test
    public static void main(String[] args) {
        String s = "abcde";
        for (int i = 1; i < 10; i++){
            int max = Math.min(i,  s.length());
            for (int j = 1; j <= max; j++){
                System.out.println(center(s.substring(0, j), i) + "|");
            }
        }
    }
}

输出:

a|
a |
ab|
 a |
ab |
abc|
 a  |
 ab |
abc |
abcd|
  a  |
 ab  |
 abc |
abcd |
abcde|
  a   |
  ab  |
 abc  |
 abcd |
abcde |
   a   |
  ab   |
  abc  |
 abcd  |
 abcde |
   a    |
   ab   |
  abc   |
  abcd  |
 abcde  |
    a    |
   ab    |
   abc   |
  abcd   |
  abcde  | 

与Mertuarez的代码相比的实际差异:

  1. 我的代码会提前计算数学值,然后一次性制作最终的居中字符串,而不是制作一个过长的字符串,然后从中获取子字符串。我认为这样更加高效,但我没有进行测试。
  2. 对于无法完美居中的文本,我的代码始终将其向左移动半个字符,而不是将其向右移动半个字符的一半时间。
  3. 对于超出指定长度的文本,我的代码始终返回从原始文本开头开始的指定长度的子字符串。

2

这是将字符串居中的另一种方法。

public static void center(String s, int length, CharSequence ch) {
    /* It works as follows
     * String centerString = String.format("|%" + (length - s.length()) + "s", s);
     * centerString = String.format("%" + -length + "s|", centerString);
     * System.out.println(centerString);
     */

    String centerString = String.format("%-" + length + "s|", String.format("|%" + (length - s.length()) + "s", s));
    System.out.println(centerString);
}

1
这是我处理Java中居中列标题的示例:
public class Test {
    public static void main(String[] args) {
        String[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September",
                "October", "November", "December" };

        // Find length of longest months value.
        int maxLengthMonth = 0;
        boolean firstValue = true;
        for (String month : months) {
            maxLengthMonth = (firstValue) ? month.length() : Math.max(maxLengthMonth, month.length());
            firstValue = false;
        }

        // Display months in column header row
        for (String month : months) {
            StringBuilder columnHeader = new StringBuilder(month);
            // Add space to front or back of columnHeader
            boolean addAtEnd = true;
            while (columnHeader.length() < maxLengthMonth) {
                if (addAtEnd) {
                    columnHeader.append(" ");
                    addAtEnd = false;
                } else {
                    columnHeader.insert(0, " ");
                    addAtEnd = true;
                }
            }
            // Display column header with two extra leading spaces for each
            // column
            String format = "  %" + Integer.toString(maxLengthMonth) + "s";
            System.out.printf(format, columnHeader);
        }
        System.out.println();

        // Display 10 rows of random numbers
        for (int i = 0; i < 10; i++) {
            for (String month : months) {
                double randomValue = Math.random() * 999999;
                String format = "  %" + Integer.toString(maxLengthMonth) + ".2f";
                System.out.printf(format, randomValue);
            }
            System.out.println();
        }
    }
}

1
这是另一个例子。让您选择在字符串开头和结尾添加不同数量的填充字符时,希望如何处理中心位置。
使用Java 11的 String::repeat
public class Strings {

    public enum Lean {
        START,
        END
    }

    public static String center(String value, int targetLength, Lean lean) {
        return center(value, targetLength, lean, ' ');
    }

    private static String center(String value, int targetLength, Lean lean, char pad) {

        if (targetLength < 1) {
            throw new IllegalArgumentException("Cannot center something into less than one space.");
        }

        int sourceLength = value.length();

        if (sourceLength == targetLength) {
            return value;
        }

        int paddingToAdd = targetLength - sourceLength;
        int half = paddingToAdd / 2;
        String spad = Character.toString(pad);
        String padding = spad.repeat(half);
        String startExtra = "";
        String endExtra = "";

        if (paddingToAdd % 2 == 1) {
            if (lean == Lean.START) {
                endExtra = spad;
            } else {
                startExtra = spad;
            }
        }

        return padding + startExtra + value + endExtra + padding;
    }
}



public class StringsTest {

    @Test
    public void centerAbcIn9LeanStart() {
        doTest(
                "abc",
                9,
                Strings.Lean.START,
                "   abc   "
        );
    }

    @Test
    public void centerAbcIn9LeanEnd() {
        doTest(
                "abc",
                9,
                Strings.Lean.END,
                "   abc   "
        );
    }

    @Test
    public void centerAbcIn10LeanStart() {
        doTest(
                "abc",
                10,
                Strings.Lean.START,
                "   abc    "
        );
    }

    @Test
    public void centerAbcIn10LeanEnd() {
        doTest(
                "abc",
                10,
                Strings.Lean.END,
                "    abc   "
        );
    }

    @Test
    public void centerAbcdIn9LeanStart() {
        doTest(
                "abcd",
                9,
                Strings.Lean.START,
                "  abcd   "
        );
    }

    @Test
    public void centerAbcdIn9LeanEnd() {
        doTest(
                "abcd",
                9,
                Strings.Lean.END,
                "   abcd  "
        );
    }

    @Test
    public void centerAbcdIn10LeanStart() {
        doTest(
                "abcd",
                10,
                Strings.Lean.START,
                "   abcd   "
        );
    }

    @Test
    public void centerAbcdIn10LeanEnd() {
        doTest(
                "abcd",
                10,
                Strings.Lean.START,
                "   abcd   "
        );
    }

    @Test
    public void centerAIn1LeanStart() {
        doTest(
                "a",
                1,
                Strings.Lean.START,
                "a"
        );
    }

    @Test
    public void centerAIn1LeanEnd() {
        doTest(
                "a",
                1,
                Strings.Lean.END,
                "a"
        );
    }

    @Test
    public void centerAIn2LeanStart() {
        doTest(
                "a",
                2,
                Strings.Lean.START,
                "a "
        );
    }

    @Test
    public void centerAIn2LeanEnd() {
        doTest(
                "a",
                2,
                Strings.Lean.END,
                " a"
        );
    }

    @Test
    public void centerAIn3LeanStart() {
        doTest(
                "a",
                3,
                Strings.Lean.START,
                " a "
        );
    }

    @Test
    public void centerAIn3LeanEnd() {
        doTest(
                "a",
                3,
                Strings.Lean.END,
                " a "
        );
    }

    @Test
    public void centerAbIn3LeanStart() {
        doTest(
                "ab",
                3,
                Strings.Lean.START,
                "ab "
        );
    }

    @Test
    public void centerAbIn3LeanEnd() {
        doTest(
                "ab",
                3,
                Strings.Lean.END,
                " ab"
        );
    }

    public void doTest(String value, int targetLength, Strings.Lean lean, String expected) {

        assertThat(
                "Test setup error: targetLength != expected.length()",
                targetLength,
                equalTo(expected.length()));

        assertThat(
                "Test setup error: value != expected.trim()",
                value,
                equalTo(expected.trim()));

        String actual = Strings.center(value, targetLength, lean);
        assertThat(actual, equalTo(expected));
    }
}

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