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

88

Ce qui suit remplacera les caractères de contrôle ASCII (raccourci pour [\x00-\x1F\x7F]):

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

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

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

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

dagnelies
la source
2
Juste comme addendum: la liste des catégories générales Unicode se trouve dans UAX # 44
McDowell
1
@Stewart: salut, avez-vous regardé la question / réponses en plus du titre?!?
dagnelies
1
@Stewart: cette autre question ne couvre que le sous-ensemble ascii des caractères non imprimables !!!
dagnelies

Réponses:

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

En savoir plus sur les expressions régulières Unicode . java.util.regexPattern/ les String.replaceAllsoutient.

Op De Cirkel
la source
En java 1.6 au moins, il n'y a pas de support pour eux. download.oracle.com/javase/6/docs/api/java/util/regex/… ... J'ai aussi essayé votre ligne, et en plus de manquer une barre oblique inverse, cela ne fonctionne tout simplement pas.
dagnelies
Cela fonctionne: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");également dans le javadoc pour la recherche de modèle dans la section de support Unicode , dit qu'il prend en charge les catégories
Op De Cirkel
Tu as raison! Je m'excuse. Je ne l'ai pas remarqué car j'ai dû ajouter les catégories Zl Zp car elles étaient principalement à l'origine de problèmes. Cela fonctionne parfaitement. Pourriez-vous s'il vous plaît apporter une mini modification à votre message afin que je puisse voter à nouveau?
dagnelies
6
Il existe également des espaces invisibles (comme 0x0200B), qui font partie du groupe \ p {Zs}. Malheureusement, celui-ci comprend également les espaces blancs normaux. Pour ceux qui essaient de filtrer une chaîne d'entrée qui ne doit contenir aucun espace, la chaîne s.replaceAll("[\\p{C}\\p{Z}]", "")fera le charme
Andrey L
1
C'est ce que je cherchais, j'essayais replaceAll("[^\\u0000-\\uFFFF]", "")mais je n'ai pas réussi
Bibaswann Bandyopadhyay
58

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

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

Mais si myStringpeut 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 remplaçant parfois seulement la moitié de la paire de substitution. Il est possible que ce soit un bogue Java plutôt qu'un comportement prévu.

L'utilisation des autres catégories constituantes est une option:

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

Cependant, 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;
    }
}
noackjr
la source
8

Vous pourriez être intéressé par les catégories Unicode «Autre, Contrôle» et éventuellement «Autre, Format» (malheureusement, ce dernier semble contenir à la fois des caractères non imprimables et imprimables).

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

Joachim Sauer
la source
Eh bien, dommage que les expressions Java ne les aient pas, mais au moins j'ai la liste en ce moment ... mieux que rien. merci
dagnelies
4

méthodes en coup 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]", "");
} 
Ali Bagheri
la source
0

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.

user1300830
la source
0

Sur la base des réponses de l' Op De Cirkel et de noackjr , voici ce que je fais pour le nettoyage général des chaînes: 1. rognage des espaces de début ou de fin, 2. dos2unix, 3. mac2unix, 4. suppression de 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.

RyanLeiTaiwan
la source
0

Je propose de supprimer les caractères non imprimables comme ci-dessous au lieu de le 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();
}
Ramesh Bathini
la source
-4

J'ai repensé le code pour les numéros de téléphone +9 (987) 124124 Extraire les chiffres d'une chaîne 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 );
}
Kairat Koibagarov
la source