Come posso sostituire i caratteri Unicode non stampabili in Java?


89

Quanto segue sostituirà i caratteri di controllo ASCII (abbreviazione di [\x00-\x1F\x7F]):

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

Quanto segue sostituirà tutti i caratteri ASCII non stampabili (abbreviazione di [\p{Graph}\x20]), inclusi i caratteri accentati:

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

Tuttavia, nessuno dei due funziona per le stringhe Unicode. Qualcuno ha un buon modo per rimuovere i caratteri non stampabili da una stringa Unicode?


2
Proprio come un addendum: l'elenco delle categorie generali Unicode può essere trovato in UAX # 44
McDowell


1
@Stewart: ciao, hai guardato le domande / risposte oltre al titolo?!?
dagnelies

1
@Stewart: quell'altra domanda copre solo il sottoinsieme ASCII di caratteri non stampabili !!!
dagnelies

Risposte:


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

Vedi di più su Unicode regex . java.util.regexPattern/ String.replaceAllli supporta.


Almeno in java 1.6, non sono supportati. download.oracle.com/javase/6/docs/api/java/util/regex/… ... Ho anche provato la tua linea, e oltre a perdere una barra rovesciata, semplicemente non funziona.
dagnelies

Funziona: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");anche nel javadoc per il pattern look nella sezione di supporto Unicode , dice che supporta le categorie
Op De Cirkel

Hai ragione! Chiedo scusa. Non l'ho notato perché ho dovuto aggiungere le categorie Zl Zp poiché quelle erano principalmente la fonte dei problemi. Funziona perfettamente. Potresti apportare una mini modifica al tuo post in modo che io possa votarlo di nuovo?
dagnelies

6
Ci sono anche caratteri di spazio vuoto invisibili (come 0x0200B), che fanno parte del gruppo \ p {Zs}. Sfortunatamente, questo include anche i normali spazi bianchi. Per coloro che stanno cercando di filtrare una stringa di input che non dovrebbe contenere spazi, la stringa s.replaceAll("[\\p{C}\\p{Z}]", "")farà il fascino
Andrey L

1
Questo è quello che stavo cercando, stavo provando replaceAll("[^\\u0000-\\uFFFF]", "")ma non ha avuto successo
Bibaswann Bandyopadhyay

58

Op De Cirkel ha perlopiù ragione. Il suo suggerimento funzionerà nella maggior parte dei casi:

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

Ma se myStringpotrebbe contenere codepoint non BMP, allora è più complicato. \p{C}contiene i codepoint surrogati di \p{Cs}. Il metodo di sostituzione sopra corromperà i codepoint non BMP sostituendo a volte solo metà della coppia surrogata. È possibile che questo sia un bug di Java piuttosto che un comportamento previsto.

L'utilizzo delle altre categorie costituenti è un'opzione:

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

Tuttavia, i caratteri surrogati solitari che non fanno parte di una coppia (ogni carattere surrogato ha un codepoint assegnato) non verranno rimossi. Un approccio non regex è l'unico modo che conosco per gestire correttamente \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

Potresti essere interessato alle categorie Unicode "Altro, Controllo" ed eventualmente "Altro, Formato" (purtroppo quest'ultimo sembra contenere sia caratteri non stampabili che stampabili).

Nelle espressioni regolari Java puoi verificarle usando \p{Cc}e \p{Cf}rispettivamente.


Beh, peccato che le espressioni java non le abbiano, ma almeno adesso ho la lista ... meglio di niente. grazie
dagnelies

5

metodi in atto per il tuo obiettivo

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

Ho usato questa semplice funzione per questo:

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;
}

Spero che questo sia utile.


0

Sulla base delle risposte di Op De Cirkel e noackjr , quanto segue è ciò che faccio per la pulizia generale delle stringhe: 1. trimming degli spazi bianchi iniziali o finali, 2. dos2unix, 3. mac2unix, 4. rimozione di tutti i "caratteri Unicode invisibili" tranne gli spazi bianchi:

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

Testato con Scala REPL.


0

Propongo di rimuovere i caratteri non stampabili come sotto invece di sostituirlo

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

Ho ridisegnato il codice per i numeri di telefono +9 (987) 124124 Estrai cifre da una stringa in 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 );
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.