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가 대부분의 표시를 제거 할 수 없다는 것입니다. ♦ 표시는 지금까지 제거 된 것을 발견 한 유일한 것입니다. ✪ ❉ ★ ✰ ❈ ❧ ✂ ❋ ⓡ ✿ ♛ 🔥와 같은 다른 표시는 제거되지 않습니다.

입력 문자열에서 이러한 모든 부호를 제거하고 다른 언어 의 문자와 문장 부호 만 유지하는 방법이 있습니까?


91
무엇을 유지하고 싶습니까?
— YCF_L

31
두 가지 문제 : EmojiParser 란 무엇입니까? 표준 라이브러리의 일부인 것 같지 않으므로이 언급은 도움이되지 않습니다. 그리고 정확히 어떤 문자를 필터링하고 싶습니까? "많은 종류의 사람들"이라고 말하지만 많은 캐릭터 그룹과 가족이 있습니다. 기준에 대해 더 알아야합니다.
— Markus Fischer

129
IDK가 당신의 동기가 무엇인지, 그것이 너무 필터링 된 텍스트 입력이라면 :하지 마십시오. 나는 a-zA-Z를 사용하는 것에 지쳤습니다. 모국어, 그림 이모티콘 또는 원하는 것을 쓰겠습니다. 캘린더 약속을 "🤦🏻‍♂️"이라고 하시겠습니까? 예, 그렇습니다 이제 나가
— 알렉산더-복원 모니카

19
정확히 유지하고 제거 할 대상을 명확히하십시오. 표면적으로 문제는 분명한 것처럼 보이지만 유니 코드의 복잡성으로 인해 명확하지 않으며 좋은 답변을 제공하는 것이 불가능합니다.
— Oleg

12
이것은 적어도 하나의 예의 의미를 파괴 할 때하고 싶은 이상한 것 같습니다.
— Eevee

답변:


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+FFFF유니 코드 ( \\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
네, 왜 이것이 다운 피트 될 수 있는지 궁금합니다. 두 번째 로이 질문을 보았을 때 정규 표현식은 가장 먼저 떠오른 것입니다. (PS는 표준 문자와 문장 부호를 찾고 있기 때문에 비슷한 것을 사용 [^\w\^\-\[\]\.!@#$%&*\(\)/+'":;~?,]하지만 강력하고 모든 전형적인 문자를 수집하려고합니다. 't 기호). 이것이 잠재적 인 해결책이기 때문에 공감되었습니다. 다른 언어 문자를 추가하려는 경우 필요에 따라 해당 언어 문자를 표현식에 추가 할 수 있습니다.
— Chris

15
@Chris 큰 문장 부호 정규식 예제는 일부 경우 나에게 충분히 넓어 보입니다. 또한 사람들은 답 의 맨 아래에 표시된 것처럼 p{L}영어 이외의 알파벳 문자를 처리 하는 전체 답변을 읽지 못할 수도 있습니다. 나는 영어가 아닌 모든 알파벳을 통해 답을 광범위하게 나열 할 수 없다는 것이 이해되기를 바랍니다.
— Nick Bull

12
이. 감사합니다 문제를 일으키는 문자 를 금지 하지 마십시오 . 허용 할 문자를 결정 하고 인코딩하십시오. 그런 다음 코드에는 명확하게 정의 된 테스트 사례 세트가 있습니다.
— jpmc26

2
나는 제안한다 "[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\s]". 이렇게하면 탭, 줄 바꿈과 같은 공백 문자뿐만 아니라 문자, 마크, 숫자, 문장 부호, 구분 기호 및 "기타, 형식"과 같은 일반 범주가 허용됩니다.
— Sean Van Gorder

81

Java에 익숙하지 않으므로 예제 코드를 인라인으로 작성하려고 시도하지 않지만 유니 코드가 각 문자의 "일반 범주"를 호출하는지 확인하는 방법입니다. 몇 글자와 문장 부호 범주가 있습니다.

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

@zwol 자세한 내용 감사합니다! 목록에 추가하겠습니다.
— Daniel Wagner

29
이것이 미래를 보장하는 답입니다. 카테고리에 따라 문자를 포함 / 제외하여 유니 코드 표준에 대한 향후 업데이트와 상관없이 개별 문자 구문 분석 및 목록 유지 관리가 필요하지 않습니다. 물론 필터링 된 범주가 대상 환경에서 허용되는 텍스트와 일치하는지 확인하려면 다른 언어 (예 : 중국어, 아랍어 등)로 된 텍스트의 커서 테스트를 수행해야합니다.
— CJBS

3
어제 내가 생각해야했던 또 다른 문제 : Tab, CR 및 LF는 모두 일반적인 카테고리 Cc (Java의 CONTROL)입니다. 거의 대부분의 레거시 제어 문자를 허용 하지 않기 때문에 특별히 허용 목록에 추가해야합니다 .
— zwol

@CJBS이 접근법의 문제점은 Java로 부분적으로 만 구현되었다는 것입니다. 예를 들어, Character.getType()당신의 여부를 말하지 않을 것이다 char(또는 int방법에 과부하가 있기 때문에 코드 포인트), 말, 이모티콘, 또는 음악 기호 나 이모티콘 문자 등 간단한 사용 사례가 있다면 괜찮을 수도 있습니다 이 길을 따라 가기-이해하기 쉬운 우아한 접근 방법이지만 요구 사항이 변경되면 중단 될 수 있습니다.
— skomisa

47

전체 이모티콘 목록 v11.0 을 기반으로 제거 할 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); 
}

유니 코드 코드 포인트 U+2705에서 Java 로의 매핑 int은 간단합니다.

int viSign = 0x2705;

또는 Java가 유니 코드 문자열을 지원하기 때문에 :

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
여기에는 최소한 두 가지 문제가 있습니다. 이모 지의 "닫힌"목록을 사용하고 있기 때문에 매년 확장해야하지만 (아마도 쉽게 해결할 수는 없지만)이 코드는 코드 포인트 시퀀스에서 올바르게 작동하지 않습니다. (예 : unicode.org/Public/emoji/11.0/emoji-zwj-sequences.txt 참조 )
— xanatos

49
이것은 기본적으로 EmojiParser에서 사용하는 것과 동일한 접근 방식이며 곧 같은 이유로 실패합니다. 새 이모티콘은 유니 코드 문자 데이터베이스에 상대적으로 자주 추가되며 현재 음수 규칙 세트에 대해 현재 정의 된 1644 이모티콘을 사용하여 솔루션을 구현하는 경우 새 이모티콘을 사용할 수있게되면 구현이 실패합니다.
— jarnbjo

20

ICU4J는 당신의 친구입니다.

UCharacter.hasBinaryProperty(UProperty.EMOJI);

icu4j 버전을 최신 상태로 유지하고 심볼 문자가 아닌 공식 유니 코드 이모티콘 만 필터링합니다. 원하는대로 다른 문자 유형을 필터링하여 결합하십시오.

추가 정보 : 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 배열 한 다음 배열을 문자열로 변환합니다.

문자와 공간 필터에 문자 방법, 구두점 잘되지를 사용하여 사용하고 있습니다. 시도가 실패했습니다 .

유니 블록 화이트 유니 블록 프로그래머 지정하여 필터를 허용한다. 시도 실패 .

유니 블록 블랙 프로그래머 지정이 아니라 허용되지 유니 블록을 사용하여 필터. 시도 실패 .

카테고리의 정적 메소드를 사용하여 필터 Character.getType. 프로그래머는 category배열에서 어떤 유형이 허용되는지 정의 할 수 있습니다 . 작품 😨😱😰😲😀.


import java.lang.Character.UnicodeBlock;그런 다음 Character.UnicodeBlock-> UnicodeBlock.
— Bernhard Barker

모든 방법으로 테스트에 실패했습니다.
— Oleg

@Oleg 아니오, white list예를 다시보십시오 .
— Marcos Zolnowski

눈이나 모니터에 문제가있는 것 같습니다. 早上 好 및 Καλημέρα
— Oleg

4
Java 언어는 최신 유니 코드 버전을 지원하는 데 약간 느립니다. 예를 들어 Java 10은 유니 코드 8 만 지원하므로 문자 클래스는 유니 코드 8 문자 만 설명합니다. 따라서 많은 이모티콘이 표시되지 않습니다 ( docs.oracle 참조). .com / javase / 10 / docs / api / java / lang / Character.html , 문자 정보는 유니 코드 표준 버전 8.0.0을 기반으로합니다. )
— xanatos


-2

RM-Emoji라는 jQuery 플러그인을 사용하십시오. 작동 방식은 다음과 같습니다.

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

텍스트에서 이모티콘을 찾기 위해 휴리스틱 알고리즘을 사용하므로 일부 이모티콘이 빠질 수있는 빠른 모드입니다. 이 .full()방법을 사용하여 전체 문자열을 스캔하고 보장 된 모든 이모티콘을 제거하십시오.


5
질문은 Java에 있었으므로 jQuery 플러그인은 여기에 관련이 없습니다.
— riorio
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.