Supprimer ✅, 🔥, ✈, ♛ et autres emojis / images / signes de ce type des chaînes Java


192

J'ai quelques chaînes avec toutes sortes d'émojis / images / signes différents.

Toutes les chaînes ne sont pas en anglais - certaines d'entre elles sont dans d'autres langues non latines, par exemple:

▓ railway??
→ Cats and dogs
I'm on 🔥
Apples ⚛ 
✅ Vi sign
♛ I'm the king ♛ 
Corée ♦ du Nord ☁  (French)
 gjør at både ◄╗ (Norwegian)
Star me ★
Star ⭐ once more
早上好 ♛ (Chinese)
Καλημέρα ✂ (Greek)
another ✓ sign ✓
добрай раніцы ✪ (Belarus)
◄ शुभ प्रभात ◄ (Hindi)
✪ ✰ ❈ ❧ Let's get together ★. We shall meet at 12/10/2018 10:00 AM at Tony's.❉

... et bien d'autres encore.

Je voudrais me débarrasser de tous ces signes / images et ne garder que les lettres (et la ponctuation) dans les différentes langues.

J'ai essayé de nettoyer les panneaux en utilisant la bibliothèque EmojiParser :

String withoutEmojis = EmojiParser.removeAllEmojis(input);

Le problème est qu'EmojiParser n'est pas en mesure de supprimer la majorité des signes. Le signe ♦ est le seul que j'ai trouvé jusqu'à présent qu'il a supprimé. D'autres signes tels que ✪ ❉ ★ ✰ ❈ ❧ ✂ ❋ ⓡ ✿ ♛ 🔥 ne sont pas supprimés.

Existe-t-il un moyen de supprimer tous ces signes des chaînes d'entrée et de ne conserver que les lettres et la ponctuation dans les différentes langues ?


91
qu'est-ce que tu veux garder?
YCF_L

31
Deux problèmes: qu'est-ce qu'EmojiParser? Ne semble pas faire partie d'une bibliothèque standard, donc cette mention n'est pas très utile. Et quels personnages voulez-vous filtrer exactement? Vous dites «beaucoup plus de ce genre», mais il existe de nombreux groupes de personnages et familles. Nous devons en savoir plus sur vos critères.
Markus Fischer

129
IDK quelles sont vos motivations derrière cela, mais si c'est trop filtrer la saisie de texte: ne le faites pas. J'en ai assez d'être obligé d'utiliser a-zA-Z. Permettez-moi d'écrire dans ma langue maternelle, ou des emojis, ou tout ce que je veux. Est-ce que je veux vraiment que mon rendez-vous soit appelé "🤦🏻‍♂️"? Oui, oui. Maintenant, sors de mon chemin.
Alexander - Rétablir Monica

19
Veuillez préciser exactement ce que vous souhaitez conserver et supprimer. En apparence, la question semble claire, mais en raison de la complexité d'Unicode, elle ne l'est pas et, à cause de cela, il est impossible de fournir une bonne réponse.
Oleg

12
cela semble être une chose étrange à vouloir faire quand elle détruit le sens d'au moins un de vos exemples?
Évoli

Réponses:


290

Au lieu de mettre sur liste noire certains éléments, que diriez-vous de créer une liste blanche des personnages que vous souhaitez conserver? De cette façon, vous n'avez pas à vous soucier de l'ajout de nouveaux emoji.

String characterFilter = "[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\p{Cs}\\s]";
String emotionless = aString.replaceAll(characterFilter,"");

Alors:

  • [\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\p{Cs}\\s]est une plage représentant tous les caractères numériques ( \\p{N}), lettre ( \\p{L}), marque ( \\p{M}), ponctuation ( \\p{P}), espaces / séparateur ( \\p{Z}), autres formats ( \\p{Cf}) et autres caractères ci-dessus U+FFFFdans Unicode ( \\p{Cs}) et caractères de nouvelle ligne ( \\s). inclut \\p{L}spécifiquement les caractères d'autres alphabets tels que le cyrillique, le latin, le kanji, etc.
  • Le ^jeu de caractères regex annule la correspondance.

Exemple:

String str = "hello world _# 皆さん、こんにちは! 私はジョンと申します。🔥";
System.out.print(str.replaceAll("[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\p{Cs}\\s]",""));
// Output:
//   "hello world _# 皆さん、こんにちは! 私はジョンと申します。"

Si vous avez besoin de plus d'informations, consultez la documentation Java pour les expressions régulières.


4
L'écart évident entre les caractères alphanumériques ASCII et les emoji est les lettres accentuées et non latines. Sans l'apport de l'OP à ce sujet, nous ne savons pas si c'est une bonne réponse (pas mon DV cependant)
Chris H

4
Ouais, je suis curieux de savoir pourquoi cela pourrait être rejeté. La seconde où j'ai vu cette question, une expression régulière a été la première chose absolue qui m'est venue à l'esprit (PS puisqu'il cherche des caractères standard et de la ponctuation, j'utiliserais quelque chose comme, [^\w\^\-\[\]\.!@#$%&*\(\)/+'":;~?,]mais c'est juste moi qui est robuste et essaye de collecter tous les caractères typiques qui ne sont pas 't symboles). A voté parce que c'est certainement une solution potentielle. S'il souhaite ajouter d'autres caractères de langue, il peut les ajouter à l'expression si nécessaire.
Chris

15
@Chris, un excellent exemple de regex de ponctuation, me semble assez étendu pour certains cas. Peut-être que les gens ne lisent pas ensuite la réponse entière - comme indiqué au bas de la réponse, p{L}gère les caractères alphabétiques non anglais . J'espère qu'il est entendu que je ne peux pas énumérer de manière approfondie tous les alphabets non anglais dans ma réponse, car cela serait pratiquement verbeux.
Nick Bull

12
Ce. S'il te plaît et merci. N'essayez pas d' interdire les caractères qui vous causent des problèmes; décidez quels caractères vous autorisez et encodez cela. Ensuite, votre code a un ensemble clairement défini de cas de test.
jpmc26

2
Je suggère "[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\s]". Cela permet les catégories générales Lettre, Marque, Nombre, Ponctuation, Séparateur et "Autre, Format", ainsi que les espaces blancs tels que tabulation et retour à la ligne.
Sean Van Gorder

81

Je ne suis pas super en Java, donc je n'essaierai pas d'écrire un exemple de code en ligne, mais la façon dont je le ferais est de vérifier ce qu'Unicode appelle "la catégorie générale" de chaque caractère. Il existe quelques catégories de lettres et de ponctuation.

Vous pouvez utiliser Character.getType pour trouver la catégorie générale d'un personnage donné. Vous devriez probablement conserver les caractères qui entrent dans ces catégories générales:

COMBINING_SPACING_MARK
CONNECTOR_PUNCTUATION
CURRENCY_SYMBOL
DASH_PUNCTUATION
DECIMAL_DIGIT_NUMBER
ENCLOSING_MARK
END_PUNCTUATION
FINAL_QUOTE_PUNCTUATION
FORMAT
INITIAL_QUOTE_PUNCTUATION
LETTER_NUMBER
LINE_SEPARATOR
LOWERCASE_LETTER
MATH_SYMBOL
MODIFIER_LETTER
MODIFIER_SYMBOL
NON_SPACING_MARK
OTHER_LETTER
OTHER_NUMBER
OTHER_PUNCTUATION
PARAGRAPH_SEPARATOR
SPACE_SEPARATOR
START_PUNCTUATION
TITLECASE_LETTER
UPPERCASE_LETTER

(Tous les personnages que vous avez répertoriés comme souhaitant spécifiquement supprimer ont une catégorie générale OTHER_SYMBOL, que je n'ai pas incluse dans la liste blanche de catégorie ci-dessus.)


1
FORMAT (Cf) doit également être conservé; cela inclut le regroupement et les remplacements directionnels, sans lesquels il est impossible d'écrire certains mots (inhabituels, certes) dans certaines langues.
zwol

@zwol Merci pour les détails! Je vais l'ajouter à la liste.
Daniel Wagner

29
Telle est la réponse d'avenir. Indépendamment des futures mises à jour de la norme Unicode, l'inclusion / exclusion de caractères en fonction de leurs catégories signifie que l'analyse individuelle des caractères et la maintenance d'une liste ne sont pas nécessaires. Bien sûr, des tests superficiels de texte dans différentes langues (par exemple chinois, arabe, etc.) doivent être effectués pour s'assurer que les catégories filtrées correspondent au texte requis pour être autorisé dans l'environnement cible.
CJBS

3
Oh, un autre problème auquel j'aurais dû penser hier: TAB, CR et LF sont tous de catégorie générale Cc (Java's CONTROL). Ceux-ci doivent être spécialement mis sur liste blanche, car vous ne voulez certainement pas autoriser la plupart des personnages de contrôle hérités.
zwol

@CJBS Le problème avec cette approche est qu'elle n'a été que partiellement implémentée en Java. Par exemple, Character.getType()ne vous dira pas si votrechar (ou intpoint de code puisque la méthode est surchargée) est, par exemple, une émoticône, ou un symbole musical, ou un caractère emoji, etc. Si vous avez un cas d'utilisation simple, cela pourrait être bien emprunter cette voie - c'est certainement une approche élégante et facile à comprendre - mais sachez qu'elle risque de se casser si les exigences changent.
skomisa

47

Sur la base de la liste complète des emojis, v11.0, vous avez 1644 points de code Unicode différents à supprimer. Par exemple, est sur cette liste comme U+2705.

Ayant la liste complète des emojis, vous devez les filtrer en utilisant des points de code . L'itération sur un seul charou bytene fonctionnera pas comme un seul point de code peut s'étendre sur plusieurs octets. Parce que Java utilise des emojis UTF-16, cela prend généralement deux chars.

String input = "ab✅cd";
for (int i = 0; i < input.length();) {
  int cp = input.codePointAt(i);
  // filter out if matches
  i += Character.charCount(cp); 
}

Le mappage du point de code Unicode U+2705vers Java intest simple:

int viSign = 0x2705;

ou puisque Java prend en charge les chaînes Unicode:

int viSign = "✅".codePointAt(0);

28
Liste très utile. Intéressant que quelque chose appelé EmojiParser avec une méthode appelée removeAllEmojis ne parvienne pas à gérer ces ... :-)
TJ Crowder

7
@Bergi: Non, car input.codePointAtne regarde que jusqu'à 2 caractères au maximum, ce qui est une limite supérieure constante. De plus (le nouveau ajouté) i += Character.charCount(cp)saute tous les caractères input.codePointAtinspectés (moins 1 dans certains cas d'angle).
David Foerster

6
@ OlivierGrégoire: String.chars()diffuse des caractères et non des points de code. Il existe une méthode distincte String.codePoints()pour cela.
David Foerster

5
Il y a au moins deux problèmes ici: vous utilisez une liste "fermée" d'emojis, donc chaque année vous devez l'étendre (mais ce n'est probablement pas facilement résoluble), et ce code ne fonctionnera probablement pas correctement avec les séquences de points de code (voir par exemple unicode.org/Public/emoji/11.0/emoji-zwj-sequences.txt )
xanatos

49
Il s'agit essentiellement de la même approche que celle utilisée par EmojiParser et elle échouera bientôt pour la même raison. De nouveaux emojis sont relativement fréquemment ajoutés à la base de données de caractères Unicode et si vous implémentez maintenant une solution utilisant les emojis 1644 actuellement définis pour un ensemble de règles négatives, l'implémentation échouera dès que de nouveaux emojis seront disponibles.
jarnbjo

20

ICU4J est votre ami.

UCharacter.hasBinaryProperty(UProperty.EMOJI);

N'oubliez pas de garder votre version d'icu4j à jour et notez que cela ne filtrera que les emoji Unicode officiels, pas les caractères de symboles. Combinez avec le filtrage des autres types de caractères comme vous le souhaitez.

Plus d'informations: http://icu-project.org/apiref/icu4j/com/ibm/icu/lang/UProperty.html#EMOJI


1
Jusqu'à ce que Java soit mis à jour pour inclure la propriété binaire Emoji, je suppose que ce serait une bonne solution. Cependant, la bibliothèque doit souvent être mise à jour pour les points de code nouvellement ajoutés.
nhahtdh

10

J'ai donné quelques exemples ci-dessous, et j'ai pensé que le latin suffisait, mais ...

Existe-t-il un moyen de supprimer tous ces signes de la chaîne d'entrée et de ne conserver que les lettres et la ponctuation dans les différentes langues?

Après l'édition, a développé une nouvelle solution, en utilisant la Character.getTypeméthode, et cela semble être le meilleur coup à cela.

package zmarcos.emoji;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class TestEmoji {

    public static void main(String[] args) {
        String[] arr = {"Remove ✅, 🔥, ✈ , ♛ and other such signs from Java string",
            "→ Cats and dogs",
            "I'm on 🔥",
            "Apples ⚛ ",
            "✅ Vi sign",
            "♛ I'm the king ♛ ",
            "Star me ★",
            "Star ⭐ once more",
            "早上好 ♛",
            "Καλημέρα ✂"};
        System.out.println("---only letters and spaces alike---\n");
        for (String input : arr) {
            int[] filtered = input.codePoints().filter((cp) -> Character.isLetter(cp) || Character.isWhitespace(cp)).toArray();
            String result = new String(filtered, 0, filtered.length);
            System.out.println(input);
            System.out.println(result);
        }

        System.out.println("\n---unicode blocks white---\n");
        Set<Character.UnicodeBlock> whiteList = new HashSet<>();
        whiteList.add(Character.UnicodeBlock.BASIC_LATIN);
        for (String input : arr) {
            int[] filtered = input.codePoints().filter((cp) -> whiteList.contains(Character.UnicodeBlock.of(cp))).toArray();
            String result = new String(filtered, 0, filtered.length);
            System.out.println(input);
            System.out.println(result);
        }

        System.out.println("\n---unicode blocks black---\n");
        Set<Character.UnicodeBlock> blackList = new HashSet<>();        
        blackList.add(Character.UnicodeBlock.EMOTICONS);
        blackList.add(Character.UnicodeBlock.MISCELLANEOUS_TECHNICAL);
        blackList.add(Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS);
        blackList.add(Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_ARROWS);
        blackList.add(Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS);
        blackList.add(Character.UnicodeBlock.ALCHEMICAL_SYMBOLS);
        blackList.add(Character.UnicodeBlock.TRANSPORT_AND_MAP_SYMBOLS);
        blackList.add(Character.UnicodeBlock.GEOMETRIC_SHAPES);
        blackList.add(Character.UnicodeBlock.DINGBATS);
        for (String input : arr) {
            int[] filtered = input.codePoints().filter((cp) -> !blackList.contains(Character.UnicodeBlock.of(cp))).toArray();
            String result = new String(filtered, 0, filtered.length);
            System.out.println(input);
            System.out.println(result);
        }
        System.out.println("\n---category---\n");
        int[] category = {Character.COMBINING_SPACING_MARK, Character.COMBINING_SPACING_MARK, Character.CONNECTOR_PUNCTUATION, /*Character.CONTROL,*/ Character.CURRENCY_SYMBOL,
            Character.DASH_PUNCTUATION, Character.DECIMAL_DIGIT_NUMBER, Character.ENCLOSING_MARK, Character.END_PUNCTUATION, Character.FINAL_QUOTE_PUNCTUATION,
            /*Character.FORMAT,*/ Character.INITIAL_QUOTE_PUNCTUATION, Character.LETTER_NUMBER, Character.LINE_SEPARATOR, Character.LOWERCASE_LETTER,
            /*Character.MATH_SYMBOL,*/ Character.MODIFIER_LETTER, /*Character.MODIFIER_SYMBOL,*/ Character.NON_SPACING_MARK, Character.OTHER_LETTER, Character.OTHER_NUMBER,
            Character.OTHER_PUNCTUATION, /*Character.OTHER_SYMBOL,*/ Character.PARAGRAPH_SEPARATOR, /*Character.PRIVATE_USE,*/
            Character.SPACE_SEPARATOR, Character.START_PUNCTUATION, /*Character.SURROGATE,*/ Character.TITLECASE_LETTER, /*Character.UNASSIGNED,*/ Character.UPPERCASE_LETTER};
        Arrays.sort(category);
        for (String input : arr) {
            int[] filtered = input.codePoints().filter((cp) -> Arrays.binarySearch(category, Character.getType(cp)) >= 0).toArray();
            String result = new String(filtered, 0, filtered.length);
            System.out.println(input);
            System.out.println(result);
        }
    }

}

Production:

---only letters and spaces alike---

Remove ✅, 🔥,  ,  and other such signs from Java string
Remove      and other such signs from Java string
 Cats and dogs
 Cats and dogs
I'm on 🔥
Im on 
Apples  
Apples  
 Vi sign
 Vi sign
 I'm the king  
 Im the king  
Star me 
Star me 
Star  once more
Star  once more
早上好 
早上好 
Καλημέρα 
Καλημέρα 

---unicode blocks white---

Remove ✅, 🔥,  ,  and other such signs from Java string
Remove , ,  ,  and other such signs from Java string
 Cats and dogs
 Cats and dogs
I'm on 🔥
I'm on 
Apples  
Apples  
 Vi sign
 Vi sign
 I'm the king  
 I'm the king  
Star me 
Star me 
Star  once more
Star  once more
早上好 

Καλημέρα 


---unicode blocks black---

Remove ✅, 🔥,  ,  and other such signs from Java string
Remove , ,  ,  and other such signs from Java string
 Cats and dogs
 Cats and dogs
I'm on 🔥
I'm on 
Apples  
Apples  
 Vi sign
 Vi sign
 I'm the king  
 I'm the king  
Star me 
Star me 
Star  once more
Star  once more
早上好 
早上好 
Καλημέρα 
Καλημέρα 

---category---

Remove ✅, 🔥,  ,  and other such signs from Java string
Remove , ,  ,  and other such signs from Java string
 Cats and dogs
 Cats and dogs
I'm on 🔥
I'm on 
Apples  
Apples  
 Vi sign
 Vi sign
 I'm the king  
 I'm the king  
Star me 
Star me 
Star  once more
Star  once more
早上好 
早上好 
Καλημέρα 
Καλημέρα 

Le code fonctionne en diffusant la chaîne en points de code. Ensuite, en utilisant lambdas pour filtrer les caractères dans unint tableau, nous convertissons ensuite le tableau en chaîne.

Les lettres et les espaces utilisent à l'aide des méthodes de caractères pour filtrer, pas bon avec la ponctuation. Échec de la tentative .

Le filtre unicode bloque le blanc en utilisant les blocs unicode que le programmeur spécifie comme autorisé. Échec de la tentative .

Le filtre noir des blocs unicode utilisant les blocs unicode que le programmeur spécifie comme non autorisé. Échec de la tentative .

Le filtre de catégorie utilisant la méthode statique Character.getType. Le programmeur peut définir dans le categorytableau quels types sont autorisés. TRAVAUX 😨😱😰😲😀.


import java.lang.Character.UnicodeBlock;, puis Character.UnicodeBlock-> UnicodeBlock.
Bernhard Barker

Toutes vos voies ont échoué aux tests.
Oleg

@Oleg non, regardez encore, l' white listexemple.
Marcos Zolnowski

Quelque chose ne va pas avec mes yeux ou mon moniteur, je ne vois pas 早上 好 et Καλημέρα
Oleg

4
Notez que le langage Java prend en charge un peu lentement les nouvelles versions d'Unicode ... Par exemple, Java 10 ne prend en charge que Unicode 8 (donc ses classes de caractères décrivent uniquement les caractères Unicode 8) ... Tant d'emojis ne sont pas présents (voir docs.oracle .com / javase / 10 / docs / api / java / lang / Character.html , les informations sur les caractères sont basées sur la norme Unicode, version 8.0.0. )
xanatos


-1

Utilisez un plugin jQuery appelé RM-Emoji. Voici comment ça fonctionne:

$('#text').remove('emoji').fast()

C'est le mode rapide qui peut manquer certains emojis car il utilise des algorithmes heuristiques pour trouver des emojis dans le texte. Utilisez la .full()méthode pour analyser la chaîne entière et supprimer tous les emojis garantis.


5
La question était en Java, donc un plugin jQuery n'est pas pertinent ici.
riorio
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.