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?


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.


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

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


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

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.


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.


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

-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 );
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.