¿Cómo puedo reemplazar los caracteres Unicode no imprimibles en Java?


88

Lo siguiente reemplazará los caracteres de control ASCII (abreviatura de [\x00-\x1F\x7F] ):

my_string.replaceAll("\\p{Cntrl}", "?");

Lo siguiente reemplazará todos los caracteres ASCII no imprimibles (abreviatura de [\p{Graph}\x20] ), incluidos los caracteres acentuados:

my_string.replaceAll("[^\\p{Print}]", "?");

Sin embargo, ninguno de los dos funciona para cadenas Unicode. ¿Alguien tiene una buena manera de eliminar caracteres no imprimibles de una cadena Unicode?


2
Solo como un apéndice: la lista de Categorías generales Unicode se puede encontrar en UAX # 44
McDowell


1
@ Stewart: hola, ¿has mirado las preguntas / respuestas además del título?
dagnelies

1
@Stewart: ¡esa otra pregunta cubre solo el subconjunto ascii de caracteres no imprimibles!
dagnelies

Respuestas:


134
my_string.replaceAll("\\p{C}", "?");

Más información sobre expresiones regulares Unicode . java.util.regexPattern/ los String.replaceAllapoya.


En java 1.6 al menos, no hay soporte para ellos. download.oracle.com/javase/6/docs/api/java/util/regex/… ... También probé tu línea, y además de perder una barra invertida, simplemente no funciona.
Dagnelies

Esto funciona: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");también en el javadoc para el aspecto del patrón en la sección de soporte Unicode , dice que admite las categorías
Op De Cirkel

¡Tienes razón! Me disculpo. No me di cuenta porque tuve que agregar las categorías Zl Zp ya que esas eran principalmente la fuente de problemas. Funciona perfectamente. ¿Podrías hacer una pequeña edición de tu publicación para que pueda votar de nuevo?
dagnelies

6
También hay espacios en blanco invisibles (como 0x0200B), que forman parte del grupo \ p {Zs}. Desafortunadamente, este también incluye espacios en blanco normales. Para aquellos que están tratando de filtrar una cadena de entrada que no debe contener ningún espacio, la cadena s.replaceAll("[\\p{C}\\p{Z}]", "")hará el encanto
Andrey L

1
Esto es lo que estaba buscando, lo estaba intentando replaceAll("[^\\u0000-\\uFFFF]", "")pero no tuve éxito
Bibaswann Bandyopadhyay

58

Op De Cirkel tiene razón. Su sugerencia funcionará en la mayoría de los casos:

myString.replaceAll("\\p{C}", "?");

Pero si myStringpuede contener puntos de código que no son BMP, entonces es más complicado. \p{C}contiene los puntos de código sustitutos de \p{Cs}. El método de reemplazo anterior corrompe los puntos de código que no son BMP reemplazando a veces solo la mitad del par sustituto. Es posible que se trate de un error de Java en lugar de un comportamiento previsto.

Usar las otras categorías constituyentes es una opción:

myString.replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "?");

Sin embargo, los personajes sustitutos solitarios que no forman parte de un par (cada personaje sustituto tiene un punto de código asignado) no se eliminarán. Un enfoque sin expresiones regulares es la única forma que conozco de manejar correctamente \p{C}:

StringBuilder newString = new StringBuilder(myString.length());
for (int offset = 0; offset < myString.length();)
{
    int codePoint = myString.codePointAt(offset);
    offset += Character.charCount(codePoint);

    // Replace invisible control characters and unused code points
    switch (Character.getType(codePoint))
    {
        case Character.CONTROL:     // \p{Cc}
        case Character.FORMAT:      // \p{Cf}
        case Character.PRIVATE_USE: // \p{Co}
        case Character.SURROGATE:   // \p{Cs}
        case Character.UNASSIGNED:  // \p{Cn}
            newString.append('?');
            break;
        default:
            newString.append(Character.toChars(codePoint));
            break;
    }
}

8

Puede que le interesen las categorías Unicode "Otro, Control" y posiblemente "Otro, Formato" (desafortunadamente, este último parece contener caracteres imprimibles y no imprimibles).

En las expresiones regulares de Java, puede verificarlas usando \p{Cc}y \p{Cf}respectivamente.


Bueno, lástima que las expresiones java no las tengan, pero al menos tengo la lista ahora mismo ... mejor que nada. gracias
dagnelies

4

métodos en golpe para tu objetivo

public static String removeNonAscii(String str)
{
    return str.replaceAll("[^\\x00-\\x7F]", "");
}

public static String removeNonPrintable(String str) // All Control Char
{
    return str.replaceAll("[\\p{C}]", "");
}

public static String removeSomeControlChar(String str) // Some Control Char
{
    return str.replaceAll("[\\p{Cntrl}\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "");
}

public static String removeFullControlChar(String str)
{
    return removeNonPrintable(str).replaceAll("[\\r\\n\\t]", "");
} 

0

He usado esta función simple para esto:

private static Pattern pattern = Pattern.compile("[^ -~]");
private static String cleanTheText(String text) {
    Matcher matcher = pattern.matcher(text);
    if ( matcher.find() ) {
        text = text.replace(matcher.group(0), "");
    }
    return text;
}

Espero que esto sea de utilidad.


0

Según las respuestas de Op De Cirkel y noackjr , lo siguiente es lo que hago para la limpieza general de cadenas: 1. recortar los espacios en blanco iniciales o finales, 2. dos2unix, 3. mac2unix, 4. eliminar todos los "caracteres Unicode invisibles" excepto los espacios en blanco:

myString.trim.replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}&&[^\\s]]", "")

Probado con Scala REPL.


0

Propongo que elimine los caracteres no imprimibles como a continuación en lugar de reemplazarlos

private String removeNonBMPCharacters(final String input) {
    StringBuilder strBuilder = new StringBuilder();
    input.codePoints().forEach((i) -> {
        if (Character.isSupplementaryCodePoint(i)) {
            strBuilder.append("?");
        } else {
            strBuilder.append(Character.toChars(i));
        }
    });
    return strBuilder.toString();
}

-4

He rediseñado el código para los números de teléfono +9 (987) 124124 Extraer dígitos de una cadena en Java

 public static String stripNonDigitsV2( CharSequence input ) {
    if (input == null)
        return null;
    if ( input.length() == 0 )
        return "";

    char[] result = new char[input.length()];
    int cursor = 0;
    CharBuffer buffer = CharBuffer.wrap( input );
    int i=0;
    while ( i< buffer.length()  ) { //buffer.hasRemaining()
        char chr = buffer.get(i);
        if (chr=='u'){
            i=i+5;
            chr=buffer.get(i);
        }

        if ( chr > 39 && chr < 58 )
            result[cursor++] = chr;
        i=i+1;
    }

    return new String( result, 0, cursor );
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.