Tworzenie znaku Unicode na podstawie jego numeru


114

Chcę wyświetlić znak Unicode w Javie. Jeśli to zrobię, działa dobrze:

String symbol = "\u2202";

symbol jest równy „∂”. To jest to czego chce.

Problem polega na tym, że znam numer Unicode i muszę na jego podstawie stworzyć symbol Unicode. Próbowałem (dla mnie) oczywistej rzeczy:

int c = 2202;
String symbol =  "\\u" + c;

Jednak w tym przypadku symbol jest równy „\ u2202”. Nie tego chcę.

Jak mogę skonstruować symbol, jeśli znam jego numer Unicode (ale tylko w czasie wykonywania - nie mogę go zakodować na stałe, jak w pierwszym przykładzie)?


1
Usuń pierwszy ukośnik odwrotny, aby zamiast uciekać przed ukośnikiem odwrotnym, zapisuje on sekwencję Unicode. Użycie „\\” mówi Javie, że chcesz wydrukować „\”, a nie używać go jako końca sekwencji sterującej dla znaków Unicode. Jeśli usuniesz pierwszy z nich, zamiast tego zmieni on sekwencję Unicode, a nie drugi lewy ukośnik. A przynajmniej tak będzie, o ile wiem.
Załóż pozew Moniki

Odpowiedzi:


73

Po prostu prześlij swoje intdo char. Możesz przekonwertować to na Stringusing Character.toString():

String s = Character.toString((char)c);

EDYTOWAĆ:

Pamiętaj tylko, że sekwencje ucieczki w kodzie źródłowym Javy ( \ubity) są w formacie HEX, więc jeśli próbujesz odtworzyć sekwencję ucieczki, będziesz potrzebować czegoś takiego int c = 0x2202.


3
To daje mi tylko kwadratowe pudełko, ࢚. Nie daje mi „∂”.
Paul Reiners,

19
Niebezpieczeństwo, Will Robinson! Nie zapominaj, że punkty kodowe Unicode niekoniecznie będą pasować do znaku . Więc musisz mieć absolutną pewność z wyprzedzeniem, że twoja wartość cjest mniejsza niż 0x10000, w przeciwnym razie to podejście okropnie się zepsuje.
David Given

1
@NickHartley Przepraszamy, nie obserwuj - czy źle odczytałeś 0x10000 dla 10000?
David Given

10
Dlatego powiedziałem „poniżej”! I muszę podkreślić, że pomimo faktu, że znaki Javy osiągają tylko 0xffff, punkty kodowe Unicode dochodzą do 0xfffff. Standard Unicode został zmieniony po zaprojektowaniu Javy. Obecnie znaki Javy technicznie przechowują słowa UTF-16, a nie punkty kodowe Unicode, a zapomnienie o tym spowoduje okropne uszkodzenie, gdy aplikacja napotka egzotyczny skrypt.
David Given

3
@DavidDzięki za Java chars go up to 0xFFFF. Nie wiedziałem tego.
Tony Ennis

128

Jeśli chcesz uzyskać jednostkę kodu zakodowaną w UTF-16 jako a char, możesz przeanalizować liczbę całkowitą i rzutować na nią, jak sugerowali inni.

Jeśli chcesz obsługiwać wszystkie punkty kodowe, użyj Character.toChars(int). Pozwoli to rozwiązać przypadki, w których punkty kodowe nie mieszczą się w jednej charwartości.

Doc mówi:

Konwertuje określony znak (punkt kodowy Unicode) na jego reprezentację w formacie UTF-16 przechowywaną w tablicy char. Jeśli określony punkt kodowy jest wartością BMP (Basic Multilingual Plane lub Plane 0), wynikowa tablica znaków ma taką samą wartość jak codePoint. Jeśli określony punkt kodowy jest dodatkowym punktem kodowym, wynikowa tablica znaków ma odpowiednią parę zastępczą.


Chociaż jest to bardziej ogólne rozwiązanie i w wielu przypadkach należy go użyć zamiast zaakceptowanej odpowiedzi, zaakceptowana odpowiedź jest bliższa konkretnemu problemowi, o który prosił Paul.
Jochem Kuijpers

2
Po pierwsze dzięki! W Scali nadal nie mogę analizować znaków, które są większe niż char. scala> "👨‍🎨".map(_.toInt).flatMap((i: Int) => Character.toChars(i)).map(_.toHexString)daje res11: scala.collection.immutable.IndexedSeq[String] = Vector(f468, 200d, f3a8) ten emotikon, „męski”, piosenkarka jest skierowana z trzech punktów kodowych U+1f468, U+200da U+1f3a8. Brakuje najbardziej znaczącej cyfry. Mogę to dodać za pomocą bitowego OR ( stackoverflow.com/a/2220476/1007926 ), ale nie wiem, jak określić, które przeanalizowane znaki zostały obcięte. Dzięki!
Peter Becich,

1
@JochemKuijpers Nie zgadzam się z tym, że „zaakceptowana odpowiedź jest bliższa konkretnemu problemowi” . OP wyraźnie zapytał: „Jak mogę skonstruować symbol, jeśli znam jego numer Unicode …?” , a zaakceptowana odpowiedź nie może działać, jeśli ten „numer Unicode” znajduje się poza BMP. Na przykład zaakceptowana odpowiedź nie powiedzie się dla prawidłowego punktu kodowego 0x1040C, ponieważ znajduje się w SMP. Jest to zła odpowiedź i należy ją poprawić lub usunąć.
skomisa

Scenariusz @skomisa OPs jest ograniczony do reprezentacji szesnastkowej sekwencji ucieczki Unicode. Jeśli masz znak, który powinien być zakodowany jako para zastępcza, to jest to odzwierciedlone w tych sekwencjach ucieczki, więc na końcu nadal działa. Jak powiedziałem, jest to bardziej ogólne rozwiązanie i powinieneś z niego skorzystać.
Jochem Kuijpers

20

Inne odpowiedzi tutaj albo obsługują tylko unicode do U + FFFF (odpowiedzi dotyczą tylko jednego wystąpienia znaku) lub nie mówią, jak dostać się do właściwego symbolu (odpowiedzi kończą się na Character.toChars () lub używają niewłaściwej metody po tym), więc tutaj również dodaję moją odpowiedź.

Aby obsługiwać również dodatkowe punkty kodowe, należy wykonać następujące czynności:

// this character:
// http://www.isthisthingon.org/unicode/index.php?page=1F&subpage=4&glyph=1F495
// using code points here, not U+n notation
// for equivalence with U+n, below would be 0xnnnn
int codePoint = 128149;
// converting to char[] pair
char[] charPair = Character.toChars(codePoint);
// and to String, containing the character we want
String symbol = new String(charPair);

// we now have str with the desired character as the first item
// confirm that we indeed have character with code point 128149
System.out.println("First code point: " + symbol.codePointAt(0));

Zrobiłem też szybki test, które metody konwersji działają, a które nie

int codePoint = 128149;
char[] charPair = Character.toChars(codePoint);

String str = new String(charPair, 0, 2);
System.out.println("First code point: " + str.codePointAt(0));    // 128149, worked
String str2 = charPair.toString();
System.out.println("Second code point: " + str2.codePointAt(0));  // 91, didn't work
String str3 = new String(charPair);
System.out.println("Third code point: " + str3.codePointAt(0));   // 128149, worked
String str4 = String.valueOf(codePoint);
System.out.println("Fourth code point: " + str4.codePointAt(0));  // 49, didn't work
String str5 = new String(new int[] {codePoint}, 0, 1);
System.out.println("Fifth code point: " + str5.codePointAt(0));   // 128149, worked

Dlaczego to nie działa jako jednolinijkowy? new String(Character.toChars(121849));psuje się w konsoli Eclipse, ale wersja trzywierszowa działa.
Noumenon

@Noumenon nie może odtworzyć problemu, działa równie dobrze dla mnie
eis

Uznanie za pójście dalej. Dlastr4 zadania nie powinno codebyć codePointzamiast tego?
skomisa

6

Pamiętaj, że charjest to typ całkowity i dlatego można mu przypisać wartość całkowitą, a także stałą char.

char c = 0x2202;//aka 8706 in decimal. \u codepoints are in hex.
String s = String.valueOf(c);

To daje mi tylko kwadratowe pudełko, ࢚. Nie daje mi „∂”.
Paul Reiners,

3
To dlatego, że 2202 nie jest tym, intktórego szukałeś. Szukałeś 0x2202. Moja wina. W każdym razie, jeśli masz intpunkt kodowy, którego szukasz, możesz po prostu rzucić go na a chari użyć (do skonstruowania, Stringjeśli chcesz).
ILMTitan,

6

Ten działał dobrze dla mnie.

  String cc2 = "2202";
  String text2 = String.valueOf(Character.toChars(Integer.parseInt(cc2, 16)));

Teraz text2 będzie miał ∂.


4
String st="2202";
int cp=Integer.parseInt(st,16);// it convert st into hex number.
char c[]=Character.toChars(cp);
System.out.println(c);// its display the character corresponding to '\u2202'.

1
Chociaż ten post może odpowiedzieć na pytanie, wymagane jest wyjaśnienie, co robisz; aby poprawić jakość i czytelność Twojej odpowiedzi
Ajil O.

1
Dzięki, naprawdę mi pomogło! Działa dobrze i jest łatwiejsze niż inne rozwiązania tutaj (tak naprawdę ludzie Java lubią nadmiernie komplikować rzeczy).
parsecer

2

Tak to się robi:

int cc = 0x2202;
char ccc = (char) Integer.parseInt(String.valueOf(cc), 16);
final String text = String.valueOf(ccc);

To rozwiązanie jest autorstwa Arne Vajhøj.


Mówisz, że to działa? Jeśli tak, to działa, ponieważ reinterpretujesz dwa tysiące, dwieście dwa jako 0x2202, co oczywiście nie jest tym samym.
dty

4
O nie, poczekaj! Wartości Unicode (sekwencje specjalne \ u w źródle Java) SĄ szesnastkowo! Więc to prawda. Po prostu oszukałeś wszystkich, mówiąc int c = 2202, co jest złe! Lepszym rozwiązaniem niż to jest łatwo powiedzieć, int c = 0x2202które zaoszczędzi ci przechodzenia przez String itp.
dty Kwietnia

3
+1 @dty: Nie ma absolutnie żadnego wezwania do środkowej char ccc...linii. Po prostu użyj, int cc = 0x2202;a potemfinal String text=String.valueOf(cc);
Andrew Coonce

2

Chociaż jest to stare pytanie, istnieje bardzo łatwy sposób na zrobienie tego w Javie 11, który został wydany dzisiaj: możesz użyć nowego przeciążenia Character.toString () :

public static String toString​(int codePoint)

Returns a String object representing the specified character (Unicode code point). The result is a string of length 1 or 2, consisting solely of the specified codePoint.

Parameters:
codePoint - the codePoint to be converted

Returns:
the string representation of the specified codePoint

Throws:
IllegalArgumentException - if the specified codePoint is not a valid Unicode code point.

Since:
11

Ponieważ ta metoda obsługuje dowolny punkt kodu Unicode, długość zwracanego ciągu niekoniecznie wynosi 1.

Kod potrzebny do przykładu podanego w pytaniu to po prostu:

    int codePoint = '\u2202';
    String s = Character.toString(codePoint); // <<< Requires JDK 11 !!!
    System.out.println(s); // Prints ∂

Takie podejście ma kilka zalet:

  • Działa dla dowolnego punktu kodu Unicode, a nie tylko tych, które można obsłużyć za pomocą pliku char.
  • Jest zwięzły i łatwo jest zrozumieć, co robi kod.
  • Zwraca wartość jako ciąg znaków zamiast a char[], co często jest tym, czego chcesz. Odpowiedź wysłana przez McDowell jest odpowiednia, jeśli chcesz, aby punkt kodowy został zwrócony jako char[].

Niektóre dodatkowe wyjaśnienia na ten temat, ponieważ ta odpowiedź od razu uświadomiły mi, jak utworzyć zmienną codePoint. Składnia powinna wyglądać następująco: int codePoint = 0x2202;Wtedy: String s = Character.toString(codePoint); // <<< Requires JDK 11 !!! Lub w jednej linii: System.out.println(Character.toString(0x2202)); // Prints ∂ Mam nadzieję, że pomoże to komuś innemu w korzystaniu z tej funkcji JDK 11.
Loathian

1

Poniższy kod zapisze 4 znaki Unicode (reprezentowane przez cyfry po przecinku) dla słowa „być” w języku japońskim. Tak, czasownik „być” w języku japońskim ma 4 znaki! Wartość znaków jest dziesiętna i została wczytana do tablicy String [] - na przykład za pomocą split. Jeśli masz ósemkę lub szesnastkę, parseInt weź również radix.

// pseudo code
// 1. init the String[] containing the 4 unicodes in decima :: intsInStrs 
// 2. allocate the proper number of character pairs :: c2s
// 3. Using Integer.parseInt (... with radix or not) get the right int value
// 4. place it in the correct location of in the array of character pairs
// 5. convert c2s[] to String
// 6. print 

String[] intsInStrs = {"12354", "12426", "12414", "12377"}; // 1.
char [] c2s = new char [intsInStrs.length * 2];  // 2.  two chars per unicode

int ii = 0;
for (String intString : intsInStrs) {
    // 3. NB ii*2 because the 16 bit value of Unicode is written in 2 chars
    Character.toChars(Integer.parseInt(intsInStrs[ii]), c2s, ii * 2 ); // 3 + 4
    ++ii; // advance to the next char
}

String symbols = new String(c2s);  // 5.
System.out.println("\nLooooonger code point: " + symbols); // 6.
// I tested it in Eclipse and Java 7 and it works.  Enjoy

1

Oto blok do drukowania znaków Unicode między \u00c0do \u00ff:

char[] ca = {'\u00c0'};
for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 16; j++) {
        String sc = new String(ca);
        System.out.print(sc + " ");
        ca[0]++;
    }
    System.out.println();
}

0

Niestety, usunięcie jednego luzu, jak wspomniano w pierwszym komentarzu (newbiedoodle), nie prowadzi do dobrego wyniku. Większość (jeśli nie wszystkie) błędów składni IDE. Powodem jest to, że format Java Escaped Unicode wymaga składni „\ uXXXX”, gdzie XXXX to 4 cyfry szesnastkowe, które są obowiązkowe. Próby złożenia tego sznurka z kawałków nie powiodły się. Oczywiście „\ u” to nie to samo, co „\\ u”. Pierwsza składnia oznacza ucieczkę „u”, druga oznacza ucieczkę odwrotną (czyli luz), po której następuje „u”. Dziwne, że na stronach Apache jest prezentowane narzędzie, które robi dokładnie to zachowanie. Ale w rzeczywistości jest to narzędzie naśladujące Escape . Apache ma własne narzędzia (nie testowałem ich), które wykonują tę pracę za Ciebie. Być może, nadal nie jest to to, co chcesz mieć.Ale to narzędzie 1mieć dobre podejście do rozwiązania. Z kombinacją opisaną powyżej (MeraNaamJoker). Moim rozwiązaniem jest utworzenie tego ciągu mimicznego Escaped, a następnie przekonwertowanie go z powrotem na Unicode (aby uniknąć rzeczywistego ograniczenia Escaped Unicode). Użyłem go do kopiowania tekstu, więc jest możliwe, że w metodzie uencode lepiej będzie użyć '\\ u' oprócz '\\\\ u'. Spróbuj.

  /**
   * Converts character to the mimic unicode format i.e. '\\u0020'.
   * 
   * This format is the Java source code format.
   * 
   *   CharUtils.unicodeEscaped(' ') = "\\u0020"
   *   CharUtils.unicodeEscaped('A') = "\\u0041"
   * 
   * @param ch  the character to convert
   * @return is in the mimic of escaped unicode string, 
   */
  public static String unicodeEscaped(char ch) {
    String returnStr;
    //String uniTemplate = "\u0000";
    final static String charEsc = "\\u";

    if (ch < 0x10) {
      returnStr = "000" + Integer.toHexString(ch);
    }
    else if (ch < 0x100) {
      returnStr = "00" + Integer.toHexString(ch);
    }
    else if (ch < 0x1000) {
      returnStr = "0" + Integer.toHexString(ch);
    }
    else
      returnStr = "" + Integer.toHexString(ch);

    return charEsc + returnStr;
  }

  /**
   * Converts the string from UTF8 to mimic unicode format i.e. '\\u0020'.
   * notice: i cannot use real unicode format, because this is immediately translated
   * to the character in time of compiling and editor (i.e. netbeans) checking it
   * instead reaal unicode format i.e. '\u0020' i using mimic unicode format '\\u0020'
   * as a string, but it doesn't gives the same results, of course
   * 
   * This format is the Java source code format.
   * 
   *   CharUtils.unicodeEscaped(' ') = "\\u0020"
   *   CharUtils.unicodeEscaped('A') = "\\u0041"
   * 
   * @param String - nationalString in the UTF8 string to convert
   * @return is the string in JAVA unicode mimic escaped
   */
  public String encodeStr(String nationalString) throws UnsupportedEncodingException {
    String convertedString = "";

    for (int i = 0; i < nationalString.length(); i++) {
      Character chs = nationalString.charAt(i);
      convertedString += unicodeEscaped(chs);
    }
    return convertedString;
  }

  /**
   * Converts the string from mimic unicode format i.e. '\\u0020' back to UTF8.
   * 
   * This format is the Java source code format.
   * 
   *   CharUtils.unicodeEscaped(' ') = "\\u0020"
   *   CharUtils.unicodeEscaped('A') = "\\u0041"
   * 
   * @param String - nationalString in the JAVA unicode mimic escaped
   * @return is the string in UTF8 string
   */
  public String uencodeStr(String escapedString) throws UnsupportedEncodingException {
    String convertedString = "";

    String[] arrStr = escapedString.split("\\\\u");
    String str, istr;
    for (int i = 1; i < arrStr.length; i++) {
      str = arrStr[i];
      if (!str.isEmpty()) {
        Integer iI = Integer.parseInt(str, 16);
        char[] chaCha = Character.toChars(iI);
        convertedString += String.valueOf(chaCha);
      }
    }
    return convertedString;
  }


-7

(ODPOWIEDŹ JEST W DOT NET 4.5, aw java musi istnieć podobne podejście)

Pochodzę z Bengalu Zachodniego w Indiach. Jak rozumiem, Twoim problemem jest ... Chcesz utworzyć podobny do „অ” (jest to litera w języku bengalskim), który ma Unicode HEX:0X0985 .

Teraz, jeśli znasz tę wartość w odniesieniu do swojego języka, to w jaki sposób utworzysz symbol Unicode dla tego języka, prawda?

W Dot Net jest to takie proste:

int c = 0X0985;
string x = Char.ConvertFromUtf32(c);

Teraz x jest twoją odpowiedzią. Ale to jest konwersja HEX przez HEX, a zamiana zdania na zdanie to praca dla badaczy: P


pytanie jest rzeczywiście dla java. Nie widzę związku z odpowiedzią .NET.
eis
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.