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.