Java文字列から✅、🔥、✈、♛などの絵文字/画像/記号を削除する


192

さまざまな種類の絵文字/画像/サインが入った文字列があります。

すべての文字列が英語であるとは限りません。たとえば、一部の文字列はラテン語以外の他の言語です。次に例を示します。

▓ 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.❉

...そしてこれらの多く。

これらすべての標識/画像を取り除き、異なる言語の文字(および句読点)のみを保持したいと思います。

EmojiParserライブラリを使用して標識をきれいにしようとしました:

String withoutEmojis = EmojiParser.removeAllEmojis(input);

問題は、EmojiParserがサインの大部分を削除できないことです。♦印は、これまでに削除した唯一の記号です。✪❉★✰❈❧✂❋✿✿♛asなどの他の標識は削除されません。

入力文字列からこれらすべての記号を削除し、異なる言語で文字と句読点のみを保持する方法はありますか?


91
何を残しておきたい?
YCF_L 2018年

31
2つの問題:EmojiParserとは何ですか?標準ライブラリの一部ではないようなので、この説明はあまり役に立ちません。そして、どの文字を正確にフィルタリングしたいですか?あなたは「この種の多く」と言いますが、多くのキャラクターグループや家族がいます。私たちはあなたの基準についてもっと知る必要があります。
Markus Fischer

129
IDKこれの背後にあるあなたの動機は何ですか、しかしそれがテキスト入力をフィルタリングしすぎるなら、そうしないでください。a-zA-Zを使わざるを得なくなった。私の母国語、絵文字、または私が好きなもので書いてみましょう。カレンダーの予定を「🤦🏻‍♂️」と呼んでもいいですか。はい、そうです。さあ、邪魔にならないで。
アレクサンダー-モニカを復活させる'27年

19
何を保持して削除するかを明確にしてください。表面的には質問は明確に見えますが、Unicodeの複雑さのために明確ではなく、そのため適切な回答を提供することは不可能です。
Oleg

12
これは、少なくとも1つの例の意味を破壊するときに行うのは奇妙なことのように思われますか?
Eevee 2018年

回答:


290

一部の要素をブラックリストに登録する代わりに、保持したいキャラクターのホワイトリストを作成してみませんか?これにより、新しい絵文字が追加されるたびに心配する必要がなくなります。

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

そう:

  • [\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\p{Cs}\\s]すべての数値(\\p{N})、文字(\\p{L})、マーク(\\p{M})、句読点(\\p{P})、空白/区切り文字(\\p{Z})、その他のフォーマット(\\p{Cf})およびその他の上記のU+FFFFUnicode \\p{Cs}\\s)文字、および改行()文字を表す範囲です。\\p{L}具体的には、キリル文字、ラテン語、漢字など、他のアルファベットの文字が含まれます。
  • ^正規表現の文字セットでは、一致を否定します。

例:

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 _# 皆さん、こんにちは! 私はジョンと申します。"

詳細については、Javaのドキュメントで正規表現を確認してください。


4
ASCII英数字と絵文字の間の明らかなギャップは、アクセント文字と非ラテン文字です。これらに関するOPの入力がないと、これが適切な答えであるかどうかはわかりません(私のDVではありません)
Chris H

4
ええ、なぜこれが反対投票になるのか興味があります。2番目にこの質問を見たとき、最初に思い浮かんだのは正規表現でした(PSは標準的な文字と句読点を探しているので、私は次のようなものを使用しますが[^\w\^\-\[\]\.!@#$%&*\(\)/+'":;~?,]、それは私が堅牢で、一般的な文字をすべて収集しようとしているだけです't記号)。これは間違いなく潜在的なソリューションなので、賛成です。他の言語の文字を追加したい場合は、必要に応じてそれらを式に追加できます。
Chris

15
@Chrisの優れた句読点の正規表現の例は、場合によっては十分に広範囲に見えます。また、回答全体を読んでいない可能性もあります。回答の下部に記載されているように、p{L}英語以外のアルファベット文字を処理します。私の回答では、英語以外のすべてのアルファベットを広範囲にわたって列挙することはできないことを理解していると思います。
Nick Bull

12
この。どうぞよろしくお願いいたします。問題の原因となる文字を禁止しないでください。許可する文字を決定しそれをエンコードします。次に、コードには明確に定義された一連のテストケースがあります。
jpmc26 2018年

2
お勧めし"[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\s]"ます。これにより、一般的なカテゴリである文字、マーク、数字、句読点、区切り文字、「その他、フォーマット」だけでなく、タブや改行などの空白文字も許可されます。
Sean Van Gorder

81

私はJavaに精通していないので、コード例をインラインで記述しようとはしませんが、これを行う方法は、Unicodeが各文字の「一般カテゴリ」と呼ぶものをチェックすることです。いくつかの文字と句読点のカテゴリがあります。

Character.getTypeを使用して、特定のキャラクターの一般的なカテゴリを見つけることができます。次の一般的なカテゴリに該当する文字を保持する必要があります。

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

(特に削除を希望するものとしてリストしたすべてのキャラクターOTHER_SYMBOLには、上記のカテゴリのホワイトリストに含まれていない一般的なカテゴリがあります。)


1
FORMAT(Cf)も保持する必要があります。これには、一部の言語で特定の(異常な、確かに)単語を書くことができないクラスタリングと方向のオーバーライドが含まれます。
zwol 2018年

@zwol詳細をありがとう!リストに追加します。
Daniel Wagner

29
これは将来に備えた答えです。Unicode標準の将来の更新に関係なく、カテゴリに基づいて文字を含める/除外するということは、文字の個別の解析とリストの保守が不要になることを意味します。もちろん、さまざまな言語(中国語、アラビア語など)のテキストの大まかなテストを実行して、フィルターされたカテゴリーがターゲット環境で許可する必要のあるテキストと一致することを確認する必要があります。
CJBS 2018年

3
ああ、私が昨日考えるべきだった別の落とし穴:TAB、CR、LFはすべて一般的なカテゴリCc(JavaのCONTROL)です。従来の制御文字のほとんどを許可したくない場合がほとんどなので、これらは特別にホワイトリストに登録する必要があります。
zwol

@CJBSこのアプローチの問題は、Javaで部分的にしか実装されていないことです。たとえば、Character.getType()あなたのchar(またはintメソッドがオーバーロードされているのでコードポイント)が、たとえば、絵文字、音楽記号、絵文字などであるかどうかはわかりません。簡単な使用例がある場合は、この道をたどる-それは確かに理解しやすいエレガントなアプローチです-しかし、要件が変更されるとそれが壊れる可能性があることに注意してください。
skomisa

47

完全な絵文字リストv11.0に基づいて、削除する必要があるUnicodeのコードポイントは1644 個あります。たとえば、このリストにはU+2705です。

絵文字の完全なリストがあるため、コードポイントを使用してそれらを除外する必要があります。単一の繰り返し処理charまたはbyte単一のコードポイントとして動作しませんと、複数バイトにまたがることができます。JavaはUTF-16を使用するため、絵文字は通常2 char秒かかります。

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

UnicodeコードポイントU+2705からJavaへのマッピングintは簡単です。

int viSign = 0x2705;

またはJavaがUnicode文字列をサポートしているため:

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

28
非常に便利なリスト。興味深いことに、removeAllEmojisと呼ばれるメソッドでEmojiParserと呼ばれるものがこれらの処理に失敗する... :-)
TJ Crowder

7
@Bergi:いいえ、input.codePointAt最大2文字までしか見ないため、これは一定の上限です。また、(新しく追加された)検査さi += Character.charCount(cp)れたすべての文字をスキップしますinput.codePointAt(一部のケースではマイナス1)。
David Foerster

6
@OlivierGrégoire:String.chars()コードポイントではなく文字を介してストリーミングします。そのための別の方法がありString.codePoints()ます。
David Foerster

5
ここには少なくとも2つの問題があります。絵文字の「クローズド」リストを使用しているため、毎年それを拡張する必要があります(ただし、これはおそらく簡単に解決できません)。このコードはおそらくコードポイントシーケンスで正しく機能しません。 (たとえば、unicode.org/Public/emoji/11.0/emoji
xanatos

49
これは基本的にEmojiParserで使用されるアプローチと同じであり、同じ理由ですぐに失敗します。新しい絵文字は比較的頻繁にUnicode文字データベースに追加されます。ネガティブルールセットに現在定義されている1644絵文字を使用してソリューションを実装している場合、新しい絵文字が利用可能になるとすぐに実装は失敗します。
jarnbjo 2018年

20

ICU4Jはあなたの友達です。

UCharacter.hasBinaryProperty(UProperty.EMOJI);

icu4jのバージョンを最新の状態に保つことを忘れないでください。これにより、公式のUnicode絵文字のみが除外され、記号文字は除外されません。必要に応じて、他の文字タイプを除外することと組み合わせます。

詳細:http : //icu-project.org/apiref/icu4j/com/ibm/icu/lang/UProperty.html#EMOJI


1
JavaがEmojiバイナリプロパティを含むように更新されるまで、これは良い解決策になると思います。ただし、新しく追加されたコードポイントについては、ライブラリを頻繁に更新する必要があります。
nhahtdh

10

以下にいくつかの例を挙げ、ラテン語で十分だと思いましたが...

入力文字列からこれらのすべての記号を削除し、異なる言語で文字と句読点のみを保持する方法はありますか?

編集後、Character.getTypeメソッドを使用して新しいソリューションを開発しました。これは、これで最高のショットのようです。

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

}

出力:

---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
早上好 
早上好 
Καλημέρα 
Καλημέρα 

コードは、文字列をコードポイントにストリーミングすることで機能します。次に、ラムダを使用して文字をint配列にフィルターし、配列を文字列に変換します。

文字とスペースは、フィルタではなく、句読点との良好に文字メソッドを使用して使用しています。失敗しました

Unicodeのブロック白許可などのUnicodeブロックプログラマの指定を使用してフィルタ。失敗しました

Unicodeのブロック黒許可されていないなどのUnicodeブロックプログラマの指定を使用してフィルタ。失敗しました

カテゴリの静的メソッドを使用してフィルタCharacter.getType。プログラマーcategoryは、許可されるタイプを配列で定義できます。WORKS 😨😱😰😲😀。


import java.lang.Character.UnicodeBlock;、次にCharacter.UnicodeBlock-> UnicodeBlock
Bernhard Barker

すべての方法がテストに失敗しました。
Oleg

@Olegいいえ、white list例をもう一度見てください。
Marcos Zolnowski、2018年

何かが私の目や私のモニタが間違っている必要があり、私が見ることができない早上で好とΚαλημέρα
オレグ

4
Java言語は新しいUnicodeバージョンのサポートが少し遅いことに注意してください。たとえば、Java 10はUnicode 8のみをサポートします(そのため、その文字クラスはUnicode 8文字のみを記述します)...多くの絵文字は存在しません(docs.oracleを参照) .com / javase / 10 / docs / api / java / lang / Character.html文字情報は、Unicode Standard、バージョン8.0.0に基づいています
xanatos 2018年

0

このプロジェクトをお試しくださいsimple-emoji-4j

Emoji 12.0(2018.10.15)に対応

シンプル:

EmojiUtils.removeEmoji(str)

-1

RM-Emojiと呼ばれるjQueryプラグインを使用します。仕組みは次のとおりです。

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

これは、テキスト内の絵文字を見つけるためにヒューリスティックアルゴリズムを使用するため、一部の絵文字を見逃す可能性がある高速モードです。.full()メソッドを使用して文字列全体をスキャンし、保証されているすべての絵文字を削除します。


5
問題はJavaにあったため、jQueryプラグインはここでは関係ありません。
riorio 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.