Ant753
Ant753

Reputation: 13

How can I print Unicode characters in Java?

I have a class named "Card" that stores a character and an integer. I am passing a unicode character of a card (the Unicode vals are taken from this Wikipedia page: https://en.wikipedia.org/wiki/Playing_cards_in_Unicode) into the instance of card. Below is what the class looks like.

import java.util.ArrayList;
import java.util.Collections;

public class Card {
    protected char unicodeCard;
    protected int value;

    public Card() {}

    public Card(char unicodeCard, int value) {
        this.unicodeCard = unicodeCard;
        this.value = value;
    }

    public ArrayList<Card> buildDeck() {
        ArrayList<Card> deck = new ArrayList<>();
        deck.add(new Card('\uF0A1', 11));
        deck.add(new Card('\uF0B1', 11));
        deck.add(new Card('\uF0C1', 11));
        deck.add(new Card('\uF0D1', 11));
        deck.add(new Card('\uF0A2', 2));
        deck.add(new Card('\uF0B2', 2));
        deck.add(new Card('\uF0C2', 2));
        deck.add(new Card('\uF0D2', 2));
        deck.add(new Card('\uF0A3', 3));
        deck.add(new Card('\uF0B3', 3));
        deck.add(new Card('\uF0C3', 3));
        deck.add(new Card('\uF0D3', 3));
        deck.add(new Card('\uF0A4', 4));
        deck.add(new Card('\uF0B4', 4));
        deck.add(new Card('\uF0C4', 4));
        deck.add(new Card('\uF0D4', 4));
        deck.add(new Card('\uF0A5', 5));
        deck.add(new Card('\uF0B5', 5));
        deck.add(new Card('\uF0C5', 5));
        deck.add(new Card('\uF0D5', 5));
        deck.add(new Card('\uF0A6', 6));
        deck.add(new Card('\uF0B6', 6));
        deck.add(new Card('\uF0C6', 6));
        deck.add(new Card('\uF0D6', 6));
        deck.add(new Card('\uF0A7', 7));
        deck.add(new Card('\uF0B7', 7));
        deck.add(new Card('\uF0C7', 7));
        deck.add(new Card('\uF0D7', 7));
        deck.add(new Card('\uF0A8', 8));
        deck.add(new Card('\uF0B8', 8));
        deck.add(new Card('\uF0C8', 8));
        deck.add(new Card('\uF0D8', 8));
        deck.add(new Card('\uF0A9', 9));
        deck.add(new Card('\uF0B9', 9));
        deck.add(new Card('\uF0C9', 9));
        deck.add(new Card('\uF0D9', 9));
        deck.add(new Card('\uF0AA', 10));
        deck.add(new Card('\uF0BA', 10));
        deck.add(new Card('\uF0CA', 10));
        deck.add(new Card('\uF0DA', 10));
        deck.add(new Card('\uF0AB', 10));
        deck.add(new Card('\uF0BB', 10));
        deck.add(new Card('\uF0CB', 10));
        deck.add(new Card('\uF0DB', 10));
        deck.add(new Card('\uF0AD', 10));
        deck.add(new Card('\uF0BD', 10));
        deck.add(new Card('\uF0CD', 10));
        deck.add(new Card('\uF0DD', 10));
        deck.add(new Card('\uF0AE', 10));
        deck.add(new Card('\uF0BE', 10));
        deck.add(new Card('\uF0CE', 10));
        deck.add(new Card('\uF0DE', 10));
        return deck;
    }

    public void shuffle(ArrayList<Card> deck) {
        Collections.shuffle(deck);
    }

    public char getCardChar() {
        return this.unicodeCard;
    }
}

In my main method, I am attempting to print out the Unicode characters in the ArrayList, but all I receive from the console is a ? character. In addition, I have tried creating an instance of PrintStream with encoding set to "UTF-8" but that doesn't seem to work either. I only get outputs that look like this: . Below is what my main method looks like.

public static void main(String[] args) throws UnsupportedEncodingException {
    PrintStream out = new PrintStream(System.out, true, "UTF-8");
    Card card = new Card();
    ArrayList<Card> deck = card.buildDeck();
    for (int i = 0; i < deck.size(); i++) {
        out.println(deck.get(i).getCardChar());
    }
}

Upvotes: 1

Views: 132

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338346

tl;dr

  • Fix your incorrect hexadecimal numbers, inserting the missing leading 1 digit. Example: \u1F0A1, not \uF0A1.
  • Use integer code point, not char.
Character.toString( 0x1F0A1 )

Incorrect code points

Your code contains the wrong Unicode code point hexadecimal numbers. You failed to include the leading 1.

  • Wrong: \uF0A1
  • Right: \u1F0A1

The codepoint for Ace of Spades is 1F0A1 hexadecimal, 127,137 decimal.

But you cannot fix your code by doing a search-and-replace changing \u for \u1. Your code uses char type, which fails here.

Avoid char

The char type has been essentially broken since Java 2, and legacy since Java 5. As a 16-bit value, char is physically incapable of representing most characters.

String literal

Java source code is Unicode compliant. So you can embed the actual character you want as a string literal.

String aceOfSpades = "🂡" ; 

In this case, those playing card glyphs may be too small to read easily in a code-editor. So you may want to use code point numbers instead.

Code points

As alternatives to char & string literals, use code point integer values to work with individual characters. You’ll find …codePoint… related methods on various classes including Character, String, and StringBuilder.

Use either hexadecimal literal or decimal literal.

String aceOfSpades = Character.toString( 0x1F0A1 ) ;

Or decimal.

String aceOfSpades = Character.toString( 127_137 ) ;

Enum

Your situation is suited (pun!) to enums.

When you have a limited set of named instances known at compile-time, define an enum. An enum is a class, albeit a slightly special kind of class. So you can define fields for your additional bits of info.

package work.basil.example.enums;

// Representing each of the standard 52-card deck of French-suited playing cards.
// https://en.wikipedia.org/wiki/Standard_52-card_deck
public enum Card
{
    // Enum
    ACE_OF_SPADES ( 0x1F0A1 ), TWO_OF_SPADES ( 0x1F0A2 ), THREE_OF_SPADES ( 0x1F0A3 ),
    ACE_OF_HEARTS ( 0x1F0B1 ), TWO_OF_HEARTS ( 0x1F0B2 ), THREE_OF_HEARTS ( 0x1F0B3 ),
    ACE_OF_DIAMONDS ( 0x1F0C1 ), TWO_OF_DIAMONDS ( 0x1F0C2 ), THREE_OF_DIAMONDS ( 0x1F0C3 ),
    ACE_OF_CLUBS ( 0x1F0D1 ), TWO_OF_CLUBS ( 0x1F0D2 ), THREE_OF_CLUBS ( 0x1F0D3 );

    // Fields
    public final int codePoint;
    public final String character;

    // Constructor
    Card ( final int theCodePoint )
    {
        this.codePoint = theCodePoint;
        this.character = Character.toString ( this.codePoint );
    }
}

We can add some static methods as a convenience, to get a deck of cards in order, and a deck shuffled.

// Collection methods
public static List < Card > deckInOrder ( )
{
    return List.of ( Card.values ( ) );
}

public static List < Card > deckShuffled ( )
{
    List < Card > deck = new ArrayList <> ( Card.deckInOrder ( ) );
    Collections.shuffle ( deck );
    return deck;
}

Dump our deck to console.

List < Card > deck = Card.deckShuffled ( );
deck.stream ( ).map ( card -> card.character + " " + card.name ( ) ).forEach ( System.out :: println );
🃓 THREE_OF_CLUBS
🂱 ACE_OF_HEARTS
🃂 TWO_OF_DIAMONDS
🂡 ACE_OF_SPADES
🂣 THREE_OF_SPADES
🃒 TWO_OF_CLUBS
🃁 ACE_OF_DIAMONDS
🃃 THREE_OF_DIAMONDS
🂳 THREE_OF_HEARTS
🂲 TWO_OF_HEARTS
🃑 ACE_OF_CLUBS
🂢 TWO_OF_SPADES

We could do much more. We could add a field for nickname of each card. We could represent the suit of each card by defining a nested enum for Suit, including a field for pip (U+2660–2667), and add a field of that type Suit to Card.

Upvotes: 1

Dorado
Dorado

Reputation: 411

Let's consider Ace of Spades as an example. The Wikipedia character has the following values U+1F0A1. The Java compiler does not agree that U+1F0A1 is a valid syntax and refuses to compile.

In this scenario, you have a few options to output symbols. I think you can replace the U+ with 0x000 and the Wikipedia Unicode.

String test1 = new String(new int[] {0x0001F0A1}, 0, 1);
String test2 = String.valueOf(Character.toChars(0x0001F0A1));
String test3 = Character.toString(0x0001F0A1);

Alternatively, you can try using different Unicode specifically for the platform, i.e., \uD83C\uDCA1.

Regardless of the options you choose, the output is still Ace of Spades.

🂡

UPDATE: @g00se commented about the redundant leading zero. That's also correct.

String test1 = new String(new int[] {0x1F0A1}, 0, 1);
String test2 = String.valueOf(Character.toChars(0x1F0A1));
String test3 = Character.toString(0x1F0A1);

Still prints 🂡.

Upvotes: 0

Sravan Kumar
Sravan Kumar

Reputation: 37

public class CardGame {
public static void main(String[] args) {
    String[] ranks = {
        "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"
    };
    String[] suits = {
        "\u2660", // Spades
        "\u2665", // Hearts
        "\u2666", // Diamonds
        "\u2663"  // Clubs
    };

    System.out.println("Deck of Cards:");
    for (String suit : suits) {
        for (String rank : ranks) {
            System.out.print(rank + suit + " ");
        }
        System.out.println(); // New line after each suit
    }
}

}

Output:

Deck of Cards: A♠ 2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♥ 2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥ A♦ 2♦ 3♦ 4♦ 5♦ 6♦ 7♦ 8♦ 9♦ 10♦ J♦ Q♦ K♦ A♣ 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣

If you need randomized, you can use such way

Random random = new Random();

    // Select a random card
    String randomRank = ranks[random.nextInt(ranks.length)];
    String randomSuit = suits[random.nextInt(suits.length)];

    System.out.println("Random Card: " + randomRank + randomSuit);

Upvotes: -2

Related Questions