web-dev-qa-db-fra.com

suppression des caractères d'une plage unicode spécifique dans une chaîne

J'ai un programme qui traite des tweets en temps réel depuis l'API Twitter. Avant de les stocker, je les encode en tant que utf8. Certains caractères apparaissent dans la chaîne sous la forme?, ?? ou ??? au lieu de leurs codes unicode respectifs et causer des problèmes. Après un examen plus approfondi, j’ai découvert que les caractères problématiques provenaient du bloc "émoticônes" , U + 1F600 - U + 1F64F et du bloc "Divers Symboles et pictogrammes" , U + 1F300 - U + 1F5FF. J'ai essayé de le supprimer, mais cela a échoué car le matcher a fini par remplacer presque tous les caractères de la chaîne, pas uniquement la plage Unicode souhaitée.

String utf8Tweet = "";
        try {
            byte[] utf8Bytes = status.getText().getBytes("UTF-8");

            utf8Tweet = new String(utf8Bytes, "UTF-8");

        } 
        catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
Pattern unicodeOutliers = Pattern.compile("[\\u1f300-\\u1f64f]", Pattern.UNICODE_CASE | Pattern.Canon_EQ | Pattern.CASE_INSENSITIVE);
Matcher unicodeOutlierMatcher = unicodeOutliers.matcher(utf8Tweet);
utf8Tweet = unicodeOutlierMatcher.replaceAll(" ");

Que puis-je faire pour supprimer ces personnages?

14
Saiato

Dans le motif regex, ajoutez l'opérateur de négation ^. Pour filtrer les caractères imprimables, vous pouvez utiliser l'expression suivante [^\\x00-\\x7F] et obtenir le résultat souhaité.

import Java.io.UnsupportedEncodingException;
import Java.util.regex.Matcher;
import Java.util.regex.Pattern;

public class UTF8 {
    public static void main(String[] args) {
        String utf8Tweet = "";
        try {
            byte[] utf8Bytes = "#Hello Twitter  How are you?".getBytes("UTF-8");

            utf8Tweet = new String(utf8Bytes, "UTF-8");

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Pattern unicodeOutliers = Pattern.compile("[^\\x00-\\x7F]",
                Pattern.UNICODE_CASE | Pattern.Canon_EQ
                        | Pattern.CASE_INSENSITIVE);
        Matcher unicodeOutlierMatcher = unicodeOutliers.matcher(utf8Tweet);

        System.out.println("Before: " + utf8Tweet);
        utf8Tweet = unicodeOutlierMatcher.replaceAll(" ");
        System.out.println("After: " + utf8Tweet);
    }
}

Résultats dans la sortie suivante:

Before: #Hello Twitter  How are you?
After: #Hello Twitter   How are you?

EDIT

Pour expliquer davantage, vous pouvez également continuer à exprimer la plage avec le formulaire \u de la manière suivante [^\\u0000-\\u007F], qui correspondra à tous les caractères qui ne sont pas les 128 premiers caractères UNICODE (les mêmes qu'auparavant). Si vous souhaitez étendre la plage pour prendre en charge des caractères supplémentaires, vous pouvez le faire à l'aide de la liste de caractères UNICODE ici .

Par exemple, si vous souhaitez inclure des voyelles avec accent (utilisé en espagnol), vous devez étendre la plage à \u00FF, afin que vous ayez [^\\u0000-\\u00FF] ou [^\\x00-\\xFF]:

Before: #Hello Twitter  How are you? á é í ó ú
After: #Hello Twitter   How are you? á é í ó ú
31
juan.facorro

Tout d’abord, le bloc unicode concerné est spécifié en Java (conformément à la norme) sous la forme Caractère.UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS . Dans une regex:

s = s.replaceAll("\\p{So}+", "");
24
Joop Eggen

J'ai essayé ça. Les gammes unicode sont de emoji gammes

    class EmojiEraser{

    private static final String EMOJI_RANGE_REGEX =
                "[\uD83C\uDF00-\uD83D\uDDFF]|[\uD83D\uDE00-\uD83D\uDE4F]|[\uD83D\uDE80-\uD83D\uDEFF]|[\u2600-\u26FF]|[\u2700-\u27BF]";
        private static final Pattern PATTERN = Pattern.compile(EMOJI_RANGE_REGEX);

        /**
         * Finds and removes emojies from @param input
         * 
         * @param input the input string potentially containing emojis (comes as unicode stringfied)
         * @return input string with emojis replaced
         */
        public String eraseEmojis(String input) {
            if (Strings.isNullOrEmpty(input)) {
                return input;
            }
            Matcher matcher = PATTERN.matcher(input);
            StringBuffer sb = new StringBuffer();
            while (matcher.find()) {
                matcher.appendReplacement(sb, "");
            }
            matcher.appendTail(sb);
            return sb.toString();
        }
}
6
tick_tack_techie

En supposant que status.getText() renvoie un Java.lang.String...

byte[] utf8Bytes = status.getText().getBytes("UTF-8");
utf8Tweet = new String(utf8Bytes, "UTF-8");

L'opération de transcodage ci-dessus produit les mêmes résultats que:

utf8Tweet = status.getText();

Les chaînes Java sont implicitement UTF-16. UTF-16 et UTF-8 partagent le même jeu de caractères (Unicode). Ainsi, la transformation de l'un à l'autre et inversement donne les résultats d'origine.

Les expressions rationnelles Java supportent la plage supplémentaire en utilisant des paires de substitution . Vous pouvez les faire correspondre comme décrit dans les réponses à cette question .

Comme le note eee dans son commentaire, vous avez probablement un problème de police de caractères. Le choix d'un graphème dépend généralement des polices disponibles sur le système de l'utilisateur, de la police choisie et du type de substitution de police pris en charge par la technologie de rendu.

0
McDowell