St, 🔥, ✈, ♛ ve benzeri diğer emojileri / görüntüleri / işaretleri Java dizelerinden kaldırın


192

Onlarda farklı emojiler / resimler / işaretler her türlü bazı dizeleri var.

Tüm dizeler İngilizce değildir - bazıları diğer Latin dillerinde değildir, örneğin:

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

... ve daha birçoğu.

Tüm bu işaretlerden / görüntülerden kurtulmak ve sadece farklı dillerde harfleri (ve noktalama işaretlerini) tutmak istiyorum.

EmojiParser kütüphanesini kullanarak işaretleri temizlemeye çalıştım :

String withoutEmojis = EmojiParser.removeAllEmojis(input);

Sorun, EmojiParser'ın işaretlerin çoğunu kaldıramamasıdır. ♦ işareti, şimdiye kadar kaldırdığımı bulduğum tek işarettir. Signs ❉ ★ ✰ ❈ ❧ ✂ ❋ ⓡ ✿ ♛ 🔥 gibi diğer işaretler kaldırılmaz.

Tüm bu işaretleri giriş dizelerinden kaldırmanın ve sadece farklı dillerde harfleri ve noktalama işaretlerini tutmanın bir yolu var mı ?


91
ne tutmak istiyorsun?
YCF_L

31
İki sorun: EmojiParser nedir? Standart bir kütüphanenin bir parçası gibi görünmüyor, bu nedenle bu söz çok yararlı değil. Ve tam olarak hangi karakterleri filtrelemek istiyorsunuz? "Bu türden çok daha fazlası" diyorsunuz, ama birçok karakter grubu ve ailesi var. Kriterleriniz hakkında daha fazla bilgi sahibi olmamız gerekiyor.
Markus Fischer

129
IDK bunun arkasındaki motivasyonların ne olduğunu, ancak çok filtre metin girişi ise: etmeyin. A-zA-Z kullanmaya zorlanmaktan yoruldum. Kendi dilimde, emojilerimde ya da ne istersem yazayım. Takvim randevusunun "🤦🏻‍♂️" olarak adlandırılmasını gerçekten ister miyim? Evet evet yaparım. Şimdi yolumdan çekil.
Alexander - Monica'yı eski haline

19
Lütfen tam olarak neyi saklamak ve kaldırmak istediğinizi açıklayın. Yüzeyde soru açık gibi görünüyor, ancak Unicode'un karmaşıklığı nedeniyle değil ve bu nedenle iyi bir cevap vermek imkansız.
Oleg

12
bu, örneklerinizden en az birinin anlamını yok ettiğinde yapmak istediğiniz garip bir şey gibi görünüyor mu?
Eevee

Yanıtlar:


290

Bazı öğeleri kara listeye almak yerine, saklamak istediğiniz karakterlerin bir beyaz listesini oluşturmaya ne dersiniz? Bu şekilde eklenen her yeni emoji için endişelenmenize gerek kalmaz.

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

Yani:

  • [\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\p{Cs}\\s]Unicode ( ) ve newline ( ) karakterlerindeki yukarıdaki tüm sayısal ( \\p{N}), harf ( \\p{L}), işaret ( \\p{M}), noktalama işareti ( \\p{P}), boşluk / ayırıcı ( \\p{Z}), diğer biçimlendirme ( \\p{Cf}) ve diğer karakterleri temsil eden bir aralıktır . özellikle Kiril, Latin, Kanji gibi diğer alfabe karakterlerini içerir.U+FFFF\\p{Cs}\\s\\p{L}
  • ^Regex karakter kümesinde maçı olumsuzlar.

Misal:

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

Daha fazla bilgiye ihtiyacınız varsa, normal ifadeler için Java belgelerine bakın.


4
ASCII alfasayısal karakterler ve emoji arasındaki açık boşluk, vurgulanmış ve latin olmayan harflerdir. OP'nin bunlara girişi olmadan bunun iyi bir cevap olup olmadığını bilmiyoruz (DV'm olmasa da)
Chris H

4
Evet, bunun neden reddedileceğini merak ediyorum. Bu soruyu ikinci gördüğümde, düzenli bir ifade akla gelen mutlak ilk şeydi (PS, standart karakterler ve noktalama işaretleri aradığından, böyle bir şey kullanardım [^\w\^\-\[\]\.!@#$%&*\(\)/+'":;~?,]ama bu sadece benim sağlamım ve olan tüm tipik karakterleri toplamaya çalışıyorum 't sembolleri). Bu kesinlikle potansiyel bir çözüm olduğu için seçildi. Başka dil karakterleri eklemek istiyorsa, bunları ifadeye gerektiği gibi ekleyebilir.
Chris

15
@Chris great punctuation regex örneği, bazı durumlarda bana yeterince geniş görünüyor. Ayrıca belki de insanlar cevabın tamamını okumuyor - cevabın altında belirtildiği gibi, p{L}İngilizce olmayan alfabetik karakterleri kullanıyor . Umarım cevabımdaki İngilizce olmayan her alfabeyi kapsamlı bir şekilde listeleyemeyeceğimden anlaşılır.
Nick Bull

12
Bu. Lütfen ve teşekkür ederim. Sorunlara neden olan karakterleri yasaklamaya çalışmayın ; hangi karakterlere izin verdiğinize karar verin ve bunu kodlayın. Daha sonra kodunuz açıkça tanımlanmış test senaryolarına sahiptir.
jpmc26

2
Ben öneririm "[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\s]". Bu, Genel kategoriler olan Harf, İşaret, Sayı, Noktalama İşaretleri, Ayırıcı ve "Diğer, Biçim" ile sekme ve satırsonu gibi boşluk karakterlerine izin verir.
Sean Van Gorder

81

Java içine süper değilim, bu yüzden satır içi örnek kod yazmaya çalışmayacağım, ama bunu yapmanın yolu Unicode her karakterin "genel kategori" dediği kontrol etmektir. Birkaç harf ve noktalama kategorisi vardır.

Belirli bir karakterin genel kategorisini bulmak için Character.getType kullanabilirsiniz . Muhtemelen bu genel kategorilere giren karakterleri korumalısınız:

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

(Özellikle kaldırmak istediğiniz olarak listelediğiniz tüm karakterlerin OTHER_SYMBOL, yukarıdaki kategori beyaz listesine dahil etmediğim genel kategorisi vardır.)


1
FORMAT (Cf) da korunmalıdır; bu, bazı dillerde belirli (olağandışı, kuşkusuz) kelimeleri yazmanın imkansız olduğu kümeleme ve yön geçersiz kılmalarını içerir.
Zwol

@zwol Detaylar için teşekkürler! Listeye ekleyeceğim.
Daniel Wagner

29
Bu geleceğe dönük bir cevap. Unicode standardında gelecekte yapılacak güncellemelere bakılmaksızın, kategorilerine göre karakterleri dahil etmek / hariç tutmak, karakterlerin ayrı ayrı ayrıştırılması ve bir listenin bakımının gerekli olmadığı anlamına gelir. Tabii ki, filtrelenmiş kategorilerin hedef ortamda izin verilmesi gereken metinle eşleştiğinden emin olmak için farklı dillerdeki metinlerin (örneğin Çince, Arapça vb.) Üstünkörü testleri yapılmalıdır.
CJBS

3
Dün düşünmemiz gereken başka bir şey var: TAB, CR ve LF hepsi genel kategori Cc (Java'nın KONTROLÜ). Eğer neredeyse kesinlikle beri olanlar gerek özel, Beyaz listeye eklenecek yok eski kontrol karakterlerinin çoğu izin vermek istiyorum.
Zwol

@CJBS Bu yaklaşımla ilgili sorun, yalnızca kısmen Java'da uygulanmış olmasıdır. Örneğin, Character.getType()sizin olsun size söylemeyeceğim char(veya intyöntem aşırı beri kod noktası), diyelim ki, bir yüz ifadesi veya müzikal bir sembol veya bir emoji karakter, vb basit bir kullanım söz konusuysa o güzel olabileceğini olduğunu Bu yoldan gitmek - kesinlikle anlaşılması kolay zarif bir yaklaşımdır - ancak gereksinimler değiştiğinde bunun kırılabileceğini unutmayın.
skomisa

47

Tam Emoji Listesi'ne dayanarak , v11.0 kaldırmak için 1644 farklı Unicode kod noktaları var. Örneğin , bu listede olduğu gibidir U+2705.

Emojilerin tam listesine sahip olmak, bunları kod noktalarını kullanarak filtrelemeniz gerekir . Tek üzerinden yineleme yapmak charveya bytetek kod noktası olarak çalışmaz birden fazla bayta yayılabilir. Java UTF-16 kullandığından emojiler genellikle iki charsaniye sürer .

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 kod noktasından U+2705Java'ya eşleme intbasittir:

int viSign = 0x2705;

veya Java Unicode Dizeleri desteklediğinden:

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

28
Çok kullanışlı bir liste. RemoveAllEmojis adlı bir yöntemle EmojiParser adlı bir şeyin bunları başaramaması ilginç ... :-)
TJ Crowder

7
@Bergi: Hayır, çünkü input.codePointAtsabit bir üst sınır olan en fazla 2 karaktere kadar bakar. Ayrıca (yeni eklenen) denetlenen i += Character.charCount(cp)tüm karakterleri atlar input.codePointAt(bazı köşe durumlarda eksi 1).
David Foerster

6
@ OlivierGrégoire: String.chars()kod noktaları değil karakterler üzerinden akış. Bunun için ayrı bir yöntem String.codePoints()var.
David Foerster

5
Burada en az iki sorun var: "kapalı" bir emoji listesi kullanıyorsunuz, bu nedenle her yıl genişletmeniz gerekiyor (ancak bu muhtemelen kolayca çözülemez) ve bu kod muhtemelen kod noktaları dizileriyle doğru şekilde çalışmayacak (örnek için bakınız unicode.org/Public/emoji/11.0/emoji-zwj-sequences.txt )
Xanatos

49
Bu temel olarak EmojiParser tarafından kullanılanla aynı yaklaşımdır ve yakında aynı nedenden dolayı başarısız olacaktır. Yeni emojiler Unicode karakter veritabanına nispeten sık eklenir ve şu anda negatif bir kural kümesi için şu anda tanımlanmış 1644 emojisini kullanarak bir çözüm uyguluyorsanız, yeni emojiler kullanılabilir hale gelir gelmez uygulama başarısız olur.
jarnbjo

20

ICU4J senin arkadaşın.

UCharacter.hasBinaryProperty(UProperty.EMOJI);

İcu4j sürümünüzü güncel tutmayı unutmayın ve bunun sembol karakterlerini değil, yalnızca resmi Unicode emojisini filtreleyeceğini unutmayın. İstediğiniz gibi diğer karakter türlerini filtreleyerek birleştirin.

Daha fazla bilgi: http://icu-project.org/apiref/icu4j/com/ibm/icu/lang/UProperty.html#EMOJI


1
Java, Emoji ikili özelliğini içerecek şekilde güncellenene kadar, bu iyi bir çözüm olurdu sanırım. Yine de kütüphanenin yeni eklenen kod noktaları için sık sık güncellenmesi gerekir.
nhahtdh

10

Aşağıda bazı örnekler verdim ve Latince'nin yeterli olduğunu düşündüm, ama ...

Tüm bu işaretleri giriş dizesinden kaldırmanın ve yalnızca farklı dillerde harfleri ve noktalama işaretlerini tutmanın bir yolu var mı?

Düzenledikten sonra, Character.getTypeyöntemi kullanarak yeni bir çözüm geliştirdi ve bu en iyi çekim gibi görünüyor.

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

}

Çıktı:

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

Kod, String'i kod noktalarına aktararak çalışır. Daha sonra karakterleri bir intdiziye filtrelemek için lambdas'ı kullanarak diziyi String'e dönüştürürüz.

Harfler ve boşluklar filtreye Karakter yöntemleri, noktalama iyi değil kullanarak kullanıyorsunuz. Başarısız girişim .

Unicode bloklar beyaz unicode bloklar programcı belirtir kullanılarak filtre izin verilen. Başarısız girişim .

Unicode blokları siyah programcı belirtir olarak izin verilmeyen Unicode bloklarını kullanarak filtre. Başarısız girişim .

Kategori statik yöntem kullanılarak filtre Character.getType. Programcı categorydizide hangi türlere izin verileceğini tanımlayabilir . ÇALIŞMALARI 😨😱😰😲😀.


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

Tüm yollarınız testlerde başarısız oldu.
Oleg

@Oleg hayır, tekrar bak, white listörnek.
Marcos Zolnowski

Gözlerimde veya monitörümde bir şeyler yanlış olmalı, göremiyorum 早上 好 ve Καλημέρα
Oleg

4
Java dilinin yeni Unicode sürümlerini destekleyen biraz yavaş olduğunu unutmayın ... Örneğin Java 10 sadece Unicode 8'i destekler (bu nedenle karakter sınıfları sadece Unicode 8 karakterlerini tanımlar) ... Pek çok emoji mevcut değil (bkz. Docs.oracle .com / javase / 10 / docs / api / java / lang / Character.html , Karakter bilgileri Unicode Standardı, sürüm
8.0.0'a dayanmaktadır


-2

RM-Emoji adlı bir jQuery eklentisi kullanın. Şöyle çalışır:

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

Bu, metinde emojiyi bulmak için sezgisel algoritmalar kullandığından bazı emojileri kaçırabilecek hızlı moddur. .full()Tüm dizeyi taramak ve garantili tüm emojileri kaldırmak için yöntemi kullanın .


5
Soru Java'daydı, bu nedenle jQuery eklentisi burada alakalı değil.
riorio
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.