Wie kann ich nicht druckbare Unicode-Zeichen in Java ersetzen?

87

Folgendes ersetzt ASCII-Steuerzeichen (Abkürzung für [\x00-\x1F\x7F]):

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

Im Folgenden werden alle nicht druckbaren ASCII-Zeichen (Abkürzung für [\p{Graph}\x20]) ersetzt, einschließlich Zeichen mit Akzent:

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

Beides funktioniert jedoch nicht für Unicode-Zeichenfolgen. Hat jemand eine gute Möglichkeit, nicht druckbare Zeichen aus einer Unicode-Zeichenfolge zu entfernen?

dagnelies
quelle
2
Nur als Nachtrag: Die Liste der allgemeinen Unicode-Kategorien finden Sie in UAX # 44
McDowell
1
@Stewart: Hallo, hast du dir die Frage / Antwort neben dem Titel angesehen?!?
Dagnelies
1
@Stewart: Diese andere Frage betrifft nur die ASCII-Teilmenge nicht druckbarer Zeichen !!!
Dagnelies

Antworten:

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

Weitere Informationen zu Unicode-Regex . java.util.regexPatternIch String.replaceAllunterstütze sie.

Op De Cirkel
quelle
Zumindest in Java 1.6 gibt es keine Unterstützung für sie. download.oracle.com/javase/6/docs/api/java/util/regex/… ... Ich habe auch Ihre Zeile ausprobiert und abgesehen davon, dass ein Backslash fehlt, funktioniert es einfach nicht.
Dagnelies
Dies funktioniert: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");Auch im Javadoc für Muster-Look im Abschnitt Unicode-Unterstützung heißt es, dass es die Kategorien unterstützt
Op De Cirkel
Sie haben Recht! Ich entschuldige mich. Ich habe es nicht bemerkt, weil ich die Zl Zp-Kategorien hinzufügen musste, da diese meistens die Ursache für Probleme waren. Es funktioniert perfekt. Könnten Sie bitte eine Mini-Bearbeitung Ihres Beitrags vornehmen, damit ich ihn erneut abstimmen kann?
Dagnelies
6
Es gibt auch unsichtbare Leerzeichen (wie 0x0200B), die Teil der Gruppe \ p {Zs} sind. Leider enthält dieser auch normale Leerzeichen. Für diejenigen, die versuchen, eine Eingabezeichenfolge zu filtern, die keine Leerzeichen enthalten sollte, wird die Zeichenfolge s.replaceAll("[\\p{C}\\p{Z}]", "")den Reiz haben
Andrey L
1
Dies ist, wonach ich gesucht habe, ich habe es versucht, replaceAll("[^\\u0000-\\uFFFF]", "")aber keinen Erfolg gehabt
Bibaswann Bandyopadhyay
57

Op De Cirkel hat größtenteils recht. Sein Vorschlag wird in den meisten Fällen funktionieren:

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

Wenn myStringes sich jedoch um Nicht-BMP-Codepunkte handelt, ist dies komplizierter. \p{C}enthält die Ersatzcodepunkte von \p{Cs}. Die oben beschriebene Ersetzungsmethode beschädigt Nicht-BMP-Codepunkte, indem manchmal nur die Hälfte des Ersatzpaars ersetzt wird. Es ist möglich, dass dies eher ein Java-Fehler als ein beabsichtigtes Verhalten ist.

Die Verwendung der anderen Kategorien ist eine Option:

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

Einzelne Ersatzzeichen, die nicht Teil eines Paares sind (jedem Ersatzzeichen ist ein Codepunkt zugewiesen), werden jedoch nicht entfernt. Ein Nicht-Regex-Ansatz ist der einzige Weg, den ich richtig handhaben kann \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;
    }
}
noackjr
quelle
8

Möglicherweise interessieren Sie sich für die Unicode-Kategorien "Andere, Steuerelemente" und möglicherweise "Andere, Format" (letztere scheinen leider sowohl nicht druckbare als auch druckbare Zeichen zu enthalten).

In Java regulären Ausdrücken können Sie überprüfen , für deren Verwendung \p{Cc}und \p{Cf}sind.

Joachim Sauer
quelle
Schade, Java-Ausdrücke haben sie nicht, aber zumindest habe ich die Liste jetzt ... besser als nichts. danke
dagnelies
4

Methoden im Schlag für Ihr Ziel

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]", "");
} 
Ali Bagheri
quelle
0

Ich habe diese einfache Funktion dafür verwendet:

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

Hoffe das ist nützlich.

user1300830
quelle
0

Basierend auf den Antworten von Op De Cirkel und noackjr mache ich Folgendes für die allgemeine Zeichenfolgenreinigung: 1. Trimmen führender oder nachfolgender Leerzeichen, 2. dos2unix, 3. mac2unix, 4. Entfernen aller "unsichtbaren Unicode-Zeichen" mit Ausnahme von Leerzeichen:

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

Getestet mit Scala REPL.

RyanLeiTaiwan
quelle
0

Ich schlage vor, die nicht druckbaren Zeichen wie unten zu entfernen, anstatt sie zu ersetzen

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();
}
Ramesh Bathini
quelle
-4

Ich habe den Code für Telefonnummern +9 (987) 124124 Ziffern aus einer Zeichenfolge in Java extrahiert

 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 );
}
Kairat Koibagarov
quelle