web-dev-qa-db-fra.com

Comment remplacer des caractères Unicode non imprimables en Java?

Les éléments suivants remplaceront ASCII caractères de contrôle (raccourci pour [\x00-\x1F\x7F])):

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

Ce qui suit remplacera tous les ASCII caractères non imprimables (raccourci pour [\p{Graph}\x20]), Y compris les caractères accentués:

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

Cependant, ni ne fonctionne pour les chaînes Unicode. Quelqu'un at-il un bon moyen de supprimer les caractères non imprimables d'une chaîne Unicode?

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

En savoir plus sur expression rationnelle Unicode . Java.util.regexPattern/String.replaceAll les soutient.

122
Op De Cirkel

Op De Cirkel a généralement raison. Sa suggestion fonctionnera dans la plupart des cas:

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

Mais si myString peut contenir des points de code non BMP, c'est plus compliqué. \p{C} contient les points de code de substitution de \p{Cs}. La méthode de remplacement ci-dessus corrompra les points de code non BMP en ne remplaçant parfois que la moitié de la paire de substitution. Il est possible qu'il s'agisse d'un bogue Java plutôt que du comportement souhaité).

Utiliser les autres catégories de constituants est une option:

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

Toutefois, les caractères de substitution solitaires ne faisant pas partie d'une paire (chaque caractère de substitution a un point de code attribué) ne seront pas supprimés. Une approche non regex est le seul moyen que je connaisse pour gérer correctement \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;
    }
}
51
noackjr

Vous pouvez être intéressé par catégories Unicode"Autre, Contrôle" et éventuellement "Autre, Format" (malheureusement, ce dernier semble contenir des caractères non imprimables et imprimables).

Dans Java expressions régulières, vous pouvez les vérifier en utilisant \p{Cc} et \p{Cf} respectivement.

7
Joachim Sauer

méthodes en souffrance pour votre objectif

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

Je propose de supprimer les caractères non imprimables comme ci-dessous au lieu de les remplacer

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

J'ai utilisé cette fonction simple pour cela:

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

J'espère que c'est utile.

0
user1300830

D'après les réponses fournies par Op De Cirkel et noackjr, voici ce que je fais pour le nettoyage général des chaînes: 1. rognage des espaces de début et de fin, 2. dos2unix, 3. mac2unix, 4. supprimant tous les "caractères Unicode invisibles" sauf les espaces:

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

Testé avec Scala REPL.

0
RyanLeiTaiwan