How to format string output, so that columns are evenly centered?

Here is one way of doing it.

Since you know the longest String you will have is "Queen of Diamonds", you can base your separation on its length. The way you would do this is, for each current string, add spaces to it until its length matches the length of "Queen of Diamonds". Then you add whatever separation you want, for example a tab ("\t").

Here is a sample program:

static String[] cards = { "3 of Spades", "3 of Diamonds", "Ace of Diamonds",
            "9 of Diamonds", "2 of Diamonds", "10 of Diamonds",
            "Ace of Spades", "10 of Hearts", "King of Clubs",
            "6 of Clubs", "4 of Spades", "Queen of Hearts",
            "5 of Diamonds", "2 of Hearts", "7 of Clubs",
            "2 of Spades", "Jack of Diamonds", "3 of Hearts",
            "5 of Hearts", "4 of Hearts", "7 of Diamonds" };

static String getSeparation(int len) {
     String longest = "Queen of Diamonds";
     StringBuilder sb = new StringBuilder();
     // add spaces to match the longest string
     for(int i = 0; i < longest.length() - len; i++) {
         sb.append(" ");
     }
     sb.append("\t"); // add separation tab
     return sb.toString();
 }

static void print() {
     for(int i = 0; i < cards.length; i += 3) {
         System.out.println(cards[i] + getSeparation(cards[i].length()) +
                            cards[i + 1] + getSeparation(cards[i + 1].length()) +
                            cards[i + 2] + getSeparation(cards[i + 2].length()));
     }
}

public static void main(String[] args) {
    print();
}

Output:

3 of Spades         3 of Diamonds       Ace of Diamonds     
9 of Diamonds       2 of Diamonds       10 of Diamonds      
Ace of Spades       10 of Hearts        King of Clubs       
6 of Clubs          4 of Spades         Queen of Hearts     
5 of Diamonds       2 of Hearts         7 of Clubs          
2 of Spades         Jack of Diamonds    3 of Hearts         
5 of Hearts         4 of Hearts         7 of Diamonds 

A shorter solution would be to use String.format or System.out.printf to format the output:

static String[] cards = { "3 of Spades", "3 of Diamonds",
        "Ace of Diamonds", "9 of Diamonds", "2 of Diamonds",
        "10 of Diamonds", "Ace of Spades", "10 of Hearts", "King of Clubs",
        "6 of Clubs", "4 of Spades", "Queen of Hearts", "5 of Diamonds",
        "2 of Hearts", "7 of Clubs", "2 of Spades", "Jack of Diamonds",
        "3 of Hearts", "5 of Hearts", "4 of Hearts", "7 of Diamonds" };

static void print() {
    int spacingSeparation = 3;                   // number of spaces between columns
    int longest = "Queen of Diamonds".length();  // length of the widest column
    int spacing = longest + spacingSeparation;   // total spacing
    for (int i = 0; i < cards.length; i += 3) {
        System.out.print(String.format(
                "%-" + spacing + "s%-" + spacing + "s%-" + spacing + "s\n",  // format
                cards[i], cards[i + 1], cards[i + 2]));                      // values
    }
}

public static void main(String[] args) {
    print();
}

Output:

3 of Spades         3 of Diamonds       Ace of Diamonds     
9 of Diamonds       2 of Diamonds       10 of Diamonds      
Ace of Spades       10 of Hearts        King of Clubs       
6 of Clubs          4 of Spades         Queen of Hearts     
5 of Diamonds       2 of Hearts         7 of Clubs          
2 of Spades         Jack of Diamonds    3 of Hearts         
5 of Hearts         4 of Hearts         7 of Diamonds  

You use something similar to what you are probably using right now. It looks like you are printing out using System.out.print(); right? If so, you can use System.out.printf(); along with %#. Let me explain.

It looks like you want to print out something that looks like this.

Column 1     Column 2     Column 3
12           23           1234

Well, the easy way to solve for that would be like this.

  int c1 = 12;
  int c2 = 23;
  int c3 = 1234;

  System.out.printf("%-22s%-22s%-22s\n","Column 1","Column 2","Column 3");
  System.out.printf("%-22d%-22d%-22d\n",c1,c2,c3);

Let's explain what is going on here, there's a lot of stuff happening. First, whenever you see a % sign in System.out.printf(), it means a special (formatting in this case) action is about to follow.

Now, let's look at the parameters of the method. The way System.out.printf() works is by specifying the format of the output in the first parameter. Then, the actual outputs are the following parameters. Do you see how it starts by specifying the format with "%-22s%-22s%-22s\n"? Then, it actually outputs them, separated by commas? That's IMO the easiest way to format.

Lastly, let's look some more at that special action thing I mentioned earlier. You see how there are letters and numbers and - after the %? Those all serve purposes too. --HERE-- is a good place to learn more but I'll give you the basic rundown.

First, the negative sign specifies which side will receive padding, padding is the space between the columns that makes them look pretty. Since it is negative, it will be on the right side, (FYI, if there was no sign there, padding would be on the left) so it will print out your output, then add spaces to the right... but how many spaces?

That's where that number comes in. The 17's you see are how many spaces there will be subtracted from the length of the output. Long story short, it will plainly and simply make sure each output starts and ends at the same place. The only catch is, make sure that the number, 22, is longer than the maximum possible String. I see the longest one possible would be Queen of Diamonds so anything bigger than 19 should do it, I chose 22 cuz it looked better IMO.

Next is the letter, that letter, as you can see, changes between the 2 output statements. In this case, one says s, the other says d. Easy way to solve this is, if your output is a String, use s, if it's and int (I don't think you will need it, I just had to for my example cuz mine were ints), use d.


I'm also going with the "format" suggestion, but mine is a little different.

In your program, you're relying on your card's toString. So make that formatted in a fixed length, and then you can use them anywhere and they will take up the same space.

public String toString() {
    return String.format( "%5s of %-8s", rank, suit );
}

When you print this out, you'll have all your cards aligned on the "of" part, which I think is what you were going for in your first output column.

The "%5s" part right-aligns the rank in a field 5 characters wide, and the "%-8s" part left-aligns the suit in a field 8 characters wide (which means there are additional spaces to the right if the suit is shorter than 8 characters).

Tags:

Java