java - simbolos - Reemplazo de la puntuación de Unicode con aproximaciones ASCII
simbolos html unicode (6)
Estoy leyendo algunos archivos de texto en un programa Java y me gustaría reemplazar algunos caracteres Unicode con aproximaciones ASCII. Estos archivos finalmente se dividirán en oraciones que se envían a OpenNLP. OpenNLP no reconoce los caracteres Unicode y da resultados impropios en una serie de símbolos (simboliza "girl''s" como "girl" y "''s", pero si es una cita de Unicode, se trata como un token único) ..
Por ejemplo, la oración de origen puede contener la cita direccional de Unicode U2018 ('') y me gustaría convertirla en U0027 (''). Eventualmente voy a eliminar el resto de Unicode.
Entiendo que estoy perdiendo información y que puedo escribir expresiones regulares para convertir cada uno de estos símbolos, pero estoy preguntando si hay un código que pueda reutilizar para convertir algunos de estos símbolos.
Esto es lo que pude, pero estoy seguro de que cometeré errores / extrañaré cosas / etc .:
// double quotation (")
replacements.add(new Replacement(Pattern.compile("[/u201c/u201d/u201e/u201f/u275d/u275e]"), "/""));
// single quotation ('')
replacements.add(new Replacement(Pattern.compile("[/u2018/u2019/u201a/u201b/u275b/u275c]"), "''"));
reemplazos es una clase personalizada que luego ejecuto y aplico los reemplazos.
for (Replacement replacement : replacements) {
text = replacement.pattern.matcher(text).replaceAll(r.replacement);
}
Como puedes ver, tuve que encontrar:
- CITA ÚNICA DE LA IZQUIERDA
- CITA ÚNICA A LA DERECHA
- UNA SOLA MARCA DE COMUNICACIÓN DE LOW-9 (¿qué es esto / debería reemplazarlo?)
- LISTA DE COMUNICACIÓN DE ALTO INVERTIDO AL 9 (¿qué es esto / debería reemplazarlo?)
A cada personaje Unicode se le asigna una category . Existen dos categorías separadas para las citas:
- Puntuación, cita final (puede comportarse como Ps o Pe dependiendo del uso)
- Puntuación, cita inicial (puede comportarse como Ps o Pe dependiendo del uso)
Con estas listas, debería poder manejar todas las citas de manera adecuada, si desea codificar la expresión regular de forma manual.
Java Character.getType te da la categoría de caracteres, por ejemplo FINAL_QUOTE_PUNCTUATION
.
Ahora puede obtener la categoría de cada carácter (puntuación) y reemplazarlo con un suplemento apropiado en ASCII.
Puede utilizar las otras categorías de puntuación en consecuencia. En "Puntuación, Otros" hay algunos caracteres, por ejemplo PRIME ′
, que también puede sustituir con un apóstrofe.
Aquí hay un paquete de Python que hace un buen trabajo. Se basa en un módulo Perl Text :: Unidecode. Supongo que esto podría ser portado a Java.
http://www.tablix.org/~avian/blog/archives/2009/01/unicode_transliteration_in_python/
Encontré una tabla bastante extensa que asigna la puntuación de Unicode a sus equivalentes ASCII más cercanos .
Aquí hay más información: Símbolos del mapa y puntuación a ASCII .
Lo que he hecho para sustituciones similares es crear un Map
(generalmente HashMap
) con los caracteres Unicode como claves y su sustituto como valores.
Pseudo-java; el for
depende del tipo de contenedor de caracteres que esté utilizando como parámetro del método que realiza esto, por ejemplo, String, CharSequence, etc.
StringBuilder output = new StringBuilder();
for (each Character ''c'' in inputString)
{
Character replacement = xlateMap.get( c );
output.append( replacement != null ? replacement : c );
}
return output.toString();
Cualquier cosa en el mapa se reemplaza, cualquier cosa que no esté en el mapa no se modifica y se copia en la salida.
Seguí el enlace de @ marek-stoj y creé una aplicación de Scala que limpia unicode de las cadenas mientras mantiene la longitud de la cadena. Elimina los signos diacríticos (acentos) y utiliza el mapa sugerido por @ marek-stoj para convertir los caracteres Unicode que no son Ascii a sus aproximaciones ascii.
import java.text.Normalizer
object Asciifier {
def apply(string: String) = {
var cleaned = string
for ((unicode, ascii) <- substitutions) {
cleaned = cleaned.replaceAll(unicode, ascii)
}
// convert diacritics to a two-character form (NFD)
// http://docs.oracle.com/javase/tutorial/i18n/text/normalizerapi.html
cleaned = Normalizer.normalize(cleaned, Normalizer.Form.NFD)
// remove all characters that combine with the previous character
// to form a diacritic. Also remove control characters.
// http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
cleaned.replaceAll("[//p{InCombiningDiacriticalMarks}//p{Cntrl}]", "")
// size must not change
require(cleaned.size == string.size)
cleaned
}
val substitutions = Set(
(0x00AB, ''"''),
(0x00AD, ''-''),
(0x00B4, ''/'''),
(0x00BB, ''"''),
(0x00F7, ''/''),
(0x01C0, ''|''),
(0x01C3, ''!''),
(0x02B9, ''/'''),
(0x02BA, ''"''),
(0x02BC, ''/'''),
(0x02C4, ''^''),
(0x02C6, ''^''),
(0x02C8, ''/'''),
(0x02CB, ''`''),
(0x02CD, ''_''),
(0x02DC, ''~''),
(0x0300, ''`''),
(0x0301, ''/'''),
(0x0302, ''^''),
(0x0303, ''~''),
(0x030B, ''"''),
(0x030E, ''"''),
(0x0331, ''_''),
(0x0332, ''_''),
(0x0338, ''/''),
(0x0589, '':''),
(0x05C0, ''|''),
(0x05C3, '':''),
(0x066A, ''%''),
(0x066D, ''*''),
(0x200B, '' ''),
(0x2010, ''-''),
(0x2011, ''-''),
(0x2012, ''-''),
(0x2013, ''-''),
(0x2014, ''-''),
(0x2015, ''-''),
(0x2016, ''|''),
(0x2017, ''_''),
(0x2018, ''/'''),
(0x2019, ''/'''),
(0x201A, '',''),
(0x201B, ''/'''),
(0x201C, ''"''),
(0x201D, ''"''),
(0x201E, ''"''),
(0x201F, ''"''),
(0x2032, ''/'''),
(0x2033, ''"''),
(0x2034, ''/'''),
(0x2035, ''`''),
(0x2036, ''"''),
(0x2037, ''/'''),
(0x2038, ''^''),
(0x2039, ''<''),
(0x203A, ''>''),
(0x203D, ''?''),
(0x2044, ''/''),
(0x204E, ''*''),
(0x2052, ''%''),
(0x2053, ''~''),
(0x2060, '' ''),
(0x20E5, ''//'),
(0x2212, ''-''),
(0x2215, ''/''),
(0x2216, ''//'),
(0x2217, ''*''),
(0x2223, ''|''),
(0x2236, '':''),
(0x223C, ''~''),
(0x2264, ''<''),
(0x2265, ''>''),
(0x2266, ''<''),
(0x2267, ''>''),
(0x2303, ''^''),
(0x2329, ''<''),
(0x232A, ''>''),
(0x266F, ''#''),
(0x2731, ''*''),
(0x2758, ''|''),
(0x2762, ''!''),
(0x27E6, ''[''),
(0x27E8, ''<''),
(0x27E9, ''>''),
(0x2983, ''{''),
(0x2984, ''}''),
(0x3003, ''"''),
(0x3008, ''<''),
(0x3009, ''>''),
(0x301B, '']''),
(0x301C, ''~''),
(0x301D, ''"''),
(0x301E, ''"''),
(0xFEFF, '' '')).map { case (unicode, ascii) => (unicode.toChar.toString, ascii.toString) }
}
Si bien esto no responde exactamente a su pregunta, puede convertir su texto Unicode a US-ASCII reemplazando los caracteres que no son ASCII con ''?'' simbolos
String input = "aáeéiíoóuú"; // 10 chars.
Charset ch = Charset.forName("US-ASCII");
CharsetEncoder enc = ch.newEncoder();
enc.onUnmappableCharacter(CodingErrorAction.REPLACE);
enc.replaceWith(new byte[]{''?''});
ByteBuffer out = null;
try {
out = enc.encode(CharBuffer.wrap(input));
} catch (CharacterCodingException e) {
/* ignored, shouldn''t happen */
}
String outStr = ch.decode(out).toString();
// Prints "a?e?i?o?u?"
System.out.println(outStr);