java - imprimir - Comparando un char con un punto de código?
textarea java netbeans (5)
Java usa un modelo de 16 bits (UTF-16) para manejar caracteres, por lo que los caracteres con puntos de código> 0xFFFF se almacenan en las cadenas como pares de caracteres de 16 bits utilizando dos caracteres surrogate para representar el plano y el carácter dentro del plano.
Si desea manejar caracteres y cadenas de acuerdo con el estándar Unicode completo, debe procesar cadenas teniendo esto en cuenta.
XML se preocupa mucho por esto; es útil acceder a la clase XMLChar en Xerces (que viene con Java versión 5.0 y superior) para código relacionado con caracteres.
También es instructivo observar el procesador XSLT / XQuery de Saxon , ya que al ser una aplicación XML de buen comportamiento, debe tener en cuenta cómo Java almacena los puntos de código en cadenas. XQuery 1.0 y XPath 2.0 tienen funciones para codepoints-to-string y string-to-codepoints ; podría ser instructivo obtener una copia de Saxon y jugar con ellos para ver cómo funcionan.
¿Cuál es la forma "correcta" de comparar un punto de código con un personaje de Java? Por ejemplo:
int codepoint = String.codePointAt(0);
char token = ''/n'';
Sé que puedo hacer:
if (codepoint==(int) token)
{ ... }
pero este código parece frágil. ¿Existe un método API formal para comparar los codepoints
de codepoints
con los chars
, o la conversión del codepoint
hasta un codepoint
de codepoint
para la comparación?
La clase de Character contiene muchos métodos útiles para trabajar con puntos de código Unicode. Tenga en cuenta métodos como Character.toChars(int) que devuelven una matriz de caracteres. Si su punto de código se encuentra en el rango suplementario, entonces la matriz tendrá dos caracteres de longitud.
La forma en que desee comparar los valores depende de si desea admitir el rango completo de valores Unicode. Este código de ejemplo se puede usar para iterar a través de los puntos de código de una Cadena, probando para ver si hay una coincidencia para el carácter suplementario MATHEMATICAL_FRAKTUR_CAPITAL_G (𝔊 - U + 1D50A):
public final class CodePointIterator {
private final String sequence;
private int index = 0;
public CodePointIterator(String sequence) {
this.sequence = sequence;
}
public boolean hasNext() {
return index < sequence.length();
}
public int next() {
int codePoint = sequence.codePointAt(index);
index += Character.charCount(codePoint);
return codePoint;
}
public static void main(String[] args) {
String sample = "A" + "/uD835/uDD0A" + "B" + "C";
int match = 0x1D50A;
CodePointIterator pointIterator = new CodePointIterator(sample);
while (pointIterator.hasNext()) {
System.out.println(match == pointIterator.next());
}
}
}
Para Java 8 en adelante, se puede usar CharSequence.codePoints() :
public static void main(String[] args) {
String sample = "A" + "/uD835/uDD0A" + "B" + "C";
int match = 0x1D50A;
sample.codePoints()
.forEach(cp -> System.out.println(cp == match));
}
Creé una table para ayudar a manejar la longitud de cadena Unicode y los casos de comparación que a veces necesitan ser manejados.
Para los personajes en el plano multilingüe básico, convertir el char a un int obtendrá el punto de código. Esto corresponde a todos los valores Unicode que se pueden codificar en un solo valor de char de 16 bits. Los valores fuera de este plano (con puntos de código que exceden 0xffff) no se pueden expresar como un solo carácter. Esta es probablemente la razón por la cual no hay Character.toCodePoint (valor de char).
Para un personaje que puede representarse con un solo carácter (16 bits, plano multilingüe básico), puede obtener el código simplemente al convertir el carácter en un número entero (como sugiere la pregunta), por lo que no es necesario un método especial para realizar una conversión
Si está comparando un char con un punto de código, no necesita ninguna carcasa especial. Simplemente compare el char con el int directamente (como lo sugiere la pregunta). Si el int representa un punto de código fuera del plano multilingüe básico, el resultado siempre será falso.
Un poco de historia: cuando apareció Java en 1995, el tipo de caracteres se basaba en la especificación original " Unicode 88 ", que estaba limitada a 16 bits. Un año después, cuando se implementó Unicode 2.0, se introdujo el concepto de caracteres sustitutos para ir más allá del límite de 16 bits.
Java internamente representa todas las String
en formato UTF-16. Para los puntos de código que exceden U + FFFF, el punto de código está representado por un par sustituto, es decir, dos caracteres, siendo el primero la unidad de código de subrogación alta (en el rango / uD800- / uDBFF), el segundo es el valor bajo unidad de código sustituto (en el rango / uDC00- / uDFFF).
Desde los primeros días, todos los métodos básicos de Character
se basaban en la suposición de que un punto de código podía representarse en una char
, de modo que así son las firmas de método. Supongo que para preservar la compatibilidad con versiones anteriores que no se modificó cuando llegó Unicode 2.0 y se necesita precaución al tratar con ellos. Para citar de la documentación de Java :
- Los métodos que solo aceptan un valor de char no pueden admitir caracteres suplementarios. Tratan los valores de char de los rangos de sustitución como caracteres indefinidos. Por ejemplo, Character.isLetter (''/ uD840'') devuelve false, aunque este valor específico si es seguido por cualquier valor de bajo sustituto en una cadena representaría una letra.
- Los métodos que aceptan un valor int admiten todos los caracteres Unicode, incluidos los caracteres suplementarios. Por ejemplo, Character.isLetter (0x2F81A) devuelve verdadero porque el valor del punto de código representa una letra (un ideograma CJK).
Sin embargo, fundir el char
en un int
, como lo haces en tu muestra, funciona bien.