Xóa,,, ♛ và các biểu tượng cảm xúc / hình ảnh / dấu hiệu khác khỏi chuỗi Java


192

Tôi có một số chuỗi với tất cả các loại biểu tượng cảm xúc / hình ảnh / dấu hiệu khác nhau trong đó.

Không phải tất cả các chuỗi đều bằng tiếng Anh - một số trong số chúng bằng các ngôn ngữ không phải là tiếng Latinh khác, ví dụ:

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

... và nhiều hơn nữa trong số này.

Tôi muốn loại bỏ tất cả các dấu hiệu / hình ảnh này và chỉ giữ lại các chữ cái (và dấu câu) trong các ngôn ngữ khác nhau.

Tôi đã cố gắng làm sạch các dấu hiệu bằng thư viện EmojiParser :

String withoutEmojis = EmojiParser.removeAllEmojis(input);

Vấn đề là EmojiParser không thể loại bỏ phần lớn các dấu hiệu. Dấu hiệu ♦ là dấu hiệu duy nhất tôi tìm thấy cho đến bây giờ nó đã bị xóa. Các dấu hiệu khác như ❉ ★ ✰ ❧ ✂ ❋ ⓡ không bị xóa.

Có cách nào để loại bỏ tất cả các dấu hiệu này khỏi các chuỗi đầu vào và chỉ giữ lại các chữ cái và dấu chấm câu trong các ngôn ngữ khác nhau không?


91
những gì bạn muốn giữ?
YCF_L

31
Hai vấn đề: EmojiParser là gì? Dường như không phải là một phần của thư viện tiêu chuẩn, vì vậy đề cập này không hữu ích lắm. Và những ký tự chính xác mà bạn muốn lọc? Bạn nói "nhiều hơn nữa của loại này", nhưng có nhiều nhóm nhân vật và gia đình. Chúng tôi cần biết thêm về tiêu chí của bạn.
Markus Fischer

129
IDK động lực của bạn đằng sau điều này là gì, nhưng nếu nó quá lọc văn bản nhập: không. Tôi mệt mỏi vì bị buộc phải sử dụng a-zA-Z. Hãy để tôi viết bằng ngôn ngữ mẹ đẻ của tôi, hoặc biểu tượng cảm xúc, hoặc bất cứ điều gì tôi muốn. Tôi có thực sự muốn tôi hẹn lịch được gọi là "" không? Vâng vâng, tôi làm. Bây giờ ra khỏi đường của tôi.
Alexander - Phục hồi Monica

19
Hãy làm rõ chính xác những gì bạn muốn giữ và loại bỏ. Nhìn bề ngoài, câu hỏi có vẻ rõ ràng nhưng vì sự phức tạp của Unicode nên không phải và vì điều đó không thể đưa ra một câu trả lời hay.
Oleg

12
điều này có vẻ như là một điều kỳ lạ muốn làm khi nó phá hủy ý nghĩa của ít nhất một trong những ví dụ của bạn?
Eevee

Câu trả lời:


290

Thay vì đưa vào danh sách đen một số yếu tố, làm thế nào về việc tạo danh sách trắng các nhân vật bạn muốn giữ? Bằng cách này, bạn không cần phải lo lắng về mọi biểu tượng cảm xúc mới được thêm vào.

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

Vì thế:

  • [\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\p{Cs}\\s]là một phạm vi đại diện cho tất cả các số ( \\p{N}), chữ cái ( \\p{L}), mark ( \\p{M}), dấu chấm câu ( \\p{P}), khoảng trắng / dấu phân cách ( \\p{Z}), định dạng khác ( \\p{Cf}) và các ký tự khác ở trên U+FFFFtrong Unicode ( \\p{Cs}) và ký tự dòng mới ( \\s). \\p{L}đặc biệt bao gồm các ký tự từ các bảng chữ cái khác như Cyrillic, Latin, Kanji, v.v.
  • Bộ ^ký tự regex phủ định trận đấu.

Thí dụ:

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

Nếu bạn cần thêm thông tin, hãy xem tài liệu Java để biết regexes.


4
Khoảng cách rõ ràng giữa các ký tự chữ và số ASCII là các ký tự được nhấn và không phải là chữ Latinh. Không có đầu vào của OP về những điều này, chúng tôi không biết liệu đây có phải là một câu trả lời hay không (mặc dù không phải DV của tôi)
Chris H

4
Vâng, tôi tò mò về lý do tại sao điều này có thể bị hạ cấp. Lần thứ hai tôi thấy câu hỏi này, một biểu thức đều đặn là điều đầu tiên tuyệt đối xuất hiện (PS vì anh ấy đang tìm kiếm các ký tự chuẩn và dấu câu, tôi sử dụng một cái gì đó giống như [^\w\^\-\[\]\.!@#$%&*\(\)/+'":;~?,]nhưng đó chỉ là tôi mạnh mẽ và cố gắng thu thập tất cả các nhân vật điển hình phát sinh ký hiệu 't). Nâng cao bởi vì đây chắc chắn là một giải pháp tiềm năng. Nếu anh ta muốn thêm một số ký tự ngôn ngữ khác, anh ta có thể thêm chúng vào biểu thức nếu cần.
Chris

15
@Chris ví dụ regex chấm câu tuyệt vời, có vẻ đủ rộng đối với tôi trong một số trường hợp. Ngoài ra, có thể mọi người không đọc toàn bộ câu trả lời sau đó - như đã nêu ở dưới cùng của câu trả lời, p{L}xử lý các ký tự chữ cái không phải tiếng Anh . Tôi hy vọng nó hiểu rằng tôi không thể liệt kê rộng rãi qua mọi bảng chữ cái không phải tiếng Anh trong câu trả lời của mình vì điều đó sẽ không chính xác.
Nick Bull

12
Điều này. Xin vui lòng và cảm ơn bạn. Đừng cố gắng cấm các nhân vật gây ra vấn đề cho bạn; quyết định những ký tự bạn cho phép và mã hóa nó. Sau đó, mã của bạn có một bộ các trường hợp thử nghiệm được xác định rõ ràng.
jpmc26

2
Tôi đề nghị "[^\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{Cf}\\s]". Điều này cho phép các danh mục chung Chữ, Dấu, Số, Dấu chấm câu, Dấu phân cách và "Khác, Định dạng", cũng như các ký tự khoảng trắng như tab và dòng mới.
Sean Van Gorder

81

Tôi không thích Java, vì vậy tôi sẽ không thử viết mã ví dụ nội tuyến, nhưng cách tôi sẽ làm là kiểm tra Unicode gọi là "danh mục chung" của mỗi ký tự. Có một vài loại thư và dấu chấm câu.

Bạn có thể sử dụng Character.getType để tìm danh mục chung của một ký tự đã cho. Bạn có thể nên giữ lại những nhân vật thuộc các loại chung sau:

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

(Tất cả các ký tự bạn liệt kê muốn loại bỏ cụ thể đều có danh mục chung OTHER_SYMBOL, mà tôi không bao gồm trong danh sách trắng danh mục trên.)


1
FORMAT (Cf) cũng nên được bảo tồn; điều này bao gồm các phần ghi đè và phân cụm theo hướng, mà không có điều đó là không thể viết một số từ nhất định (bất thường, được thừa nhận) trong một số ngôn ngữ.
zwol

@zwol Cảm ơn các chi tiết! Tôi sẽ thêm nó vào danh sách.
Daniel Wagner

29
Đây là câu trả lời trong tương lai. Bất kể các bản cập nhật trong tương lai cho tiêu chuẩn Unicode, bao gồm / loại trừ các ký tự dựa trên danh mục của chúng có nghĩa là phân tích cú pháp các ký tự riêng lẻ và việc duy trì danh sách là không cần thiết. Tất nhiên, nên thực hiện kiểm tra chữ thảo văn bản bằng các ngôn ngữ khác nhau (ví dụ: tiếng Trung, tiếng Ả Rập, v.v.) để đảm bảo rằng các danh mục được lọc phù hợp với văn bản được yêu cầu cho phép trong môi trường đích.
CJBS

3
Ồ, một gotcha khác mà tôi nên nghĩ đến ngày hôm qua: TAB, CR và LF đều là loại Cc chung (KIỂM SOÁT của Java). Những người cần phải được đưa vào danh sách trắng đặc biệt, vì bạn gần như chắc chắn không muốn cho phép hầu hết các nhân vật kiểm soát di sản.
zwol

@CJBS Vấn đề với cách tiếp cận này là nó chỉ được thực hiện một phần trong Java. Ví dụ: Character.getType()sẽ không cho bạn biết liệu char(hoặc intđiểm mã của bạn vì phương thức bị quá tải), giả sử là biểu tượng cảm xúc hoặc biểu tượng âm nhạc hoặc ký tự biểu tượng cảm xúc, v.v. Nếu bạn có trường hợp sử dụng đơn giản thì có thể ổn để đi theo con đường này - đó chắc chắn là một cách tiếp cận thanh lịch dễ hiểu - nhưng lưu ý rằng nó có thể bị phá vỡ nếu yêu cầu thay đổi.
skomisa

47

Dựa trên Danh sách biểu tượng cảm xúc đầy đủ, v11.0 bạn có 1644 điểm mã Unicode khác nhau để xóa. Ví dụ là trong danh sách này như U+2705.

Có danh sách đầy đủ các biểu tượng cảm xúc, bạn cần lọc chúng bằng các điểm mã . Lặp lại qua một charhoặc bytekhông hoạt động vì điểm mã đơn có thể trải rộng trên nhiều byte. Bởi vì Java sử dụng biểu tượng cảm xúc UTF-16 thường sẽ mất hai 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); 
}

Ánh xạ từ điểm mã Unicode U+2705sang Java intrất đơn giản:

int viSign = 0x2705;

hoặc vì Java hỗ trợ Chuỗi Unicode:

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

28
Danh sách rất hữu ích. Thật thú vị khi một thứ gọi là EmojiParser với một phương thức gọi là remove ALLEmojis không xử lý được những điều này ... :-)
TJ Crowder

7
@Bergi: Không, vì input.codePointAtchỉ nhìn tối đa 2 ký tự là giới hạn trên không đổi. Ngoài ra (mới được thêm vào) i += Character.charCount(cp)bỏ qua tất cả các ký tự đã input.codePointAtkiểm tra (trừ 1 trong một số trường hợp góc).
David

6
@ OlivierGrégoire: String.chars()phát trực tiếp các ký tự không phải là mật mã. Có một phương pháp riêng String.codePoints()cho việc đó.
David

5
Có ít nhất hai vấn đề ở đây: bạn đang sử dụng danh sách biểu tượng cảm xúc "đóng", vì vậy mỗi năm bạn phải gia hạn nó (nhưng điều này có lẽ không dễ dàng giải quyết được) và mã này có thể sẽ không hoạt động chính xác với các chuỗi mã hóa (xem ví dụ unicode.org/Public/emoji/11.0/emoji-zwj-
resultences.txt

49
Về cơ bản, đây là cách tiếp cận tương tự như được sử dụng bởi EmojiParser và nó sẽ sớm thất bại vì lý do tương tự. Biểu tượng cảm xúc mới tương đối thường xuyên được thêm vào cơ sở dữ liệu ký tự Unicode và nếu bạn hiện đang thực hiện giải pháp sử dụng biểu tượng cảm xúc 1644 hiện được xác định cho bộ quy tắc phủ định, việc triển khai sẽ thất bại ngay khi có biểu tượng cảm xúc mới.
jarnbjo

20

ICU4J là bạn của bạn.

UCharacter.hasBinaryProperty(UProperty.EMOJI);

Hãy nhớ luôn cập nhật phiên bản icu4j của bạn và lưu ý rằng điều này sẽ chỉ lọc ra biểu tượng cảm xúc Unicode chính thức, không phải ký tự biểu tượng. Kết hợp với việc lọc ra các loại ký tự khác như mong muốn.

Thêm thông tin: http://icu-project.org/apiref/icu4j/com/ibm/icu/lang/UProperty.html#EMOJI


1
Cho đến khi Java được cập nhật để bao gồm thuộc tính nhị phân Emoji, tôi đoán đây sẽ là một giải pháp tốt. Thư viện cần phải được cập nhật thường xuyên cho các điểm mã mới được thêm vào.
nhahtdh

10

Tôi đã đưa ra một số ví dụ dưới đây và nghĩ rằng tiếng Latin là đủ, nhưng ...

Có cách nào để loại bỏ tất cả các dấu hiệu này khỏi chuỗi đầu vào và chỉ giữ lại các chữ cái và dấu chấm câu trong các ngôn ngữ khác nhau không?

Sau khi chỉnh sửa, đã phát triển một giải pháp mới, sử dụng Character.getTypephương pháp và dường như đó là cách tốt nhất để thực hiện điều này.

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

}

Đầu ra:

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

Mã này hoạt động bằng cách truyền Chuỗi đến các điểm mã. Sau đó, sử dụng lambdas để lọc các ký tự thành một intmảng, sau đó chúng tôi chuyển đổi mảng thành Chuỗi.

Các chữ cái và dấu cách đang sử dụng các phương thức Ký tự để lọc, không tốt với dấu câu. Thất bại .

Bộ lọc unicode chặn bộ lọc trắng bằng cách sử dụng các khối unicode mà lập trình viên chỉ định là được phép. Thất bại .

Các khối unicode đen lọc sử dụng các khối unicode các quy định cụ thể lập trình viên như không được phép. Thất bại .

Bộ lọc danh mục sử dụng phương thức tĩnh Character.getType. Các lập trình viên có thể định nghĩa trong categorymảng những loại được cho phép. CÔNG TRÌNH .


import java.lang.Character.UnicodeBlock;, sau đó Character.UnicodeBlock-> UnicodeBlock.
Bernhard Barker

Tất cả các cách của bạn đã thất bại trong các bài kiểm tra.
Oleg

@Oleg không, nhìn lại, white liství dụ.
Marcos Zolnowski

Một cái gì đó phải sai với mắt hoặc màn hình của tôi, tôi không thể nhìn thấy là 早上 好 và Καλημέρα
Oleg

4
Lưu ý rằng ngôn ngữ Java hơi chậm khi hỗ trợ các phiên bản Unicode mới hơn ... Ví dụ: Java 10 chỉ hỗ trợ Unicode 8 (vì vậy các lớp ký tự của nó chỉ mô tả các ký tự Unicode 8) ... Rất nhiều biểu tượng cảm xúc không xuất hiện (xem docs.oracle .com / javase / 10 / docs / api / java / lang / Character.html , thông tin nhân vật dựa trên Tiêu chuẩn Unicode, phiên bản
8.0.0


-1

Sử dụng một plugin jQuery có tên là RM-Emoji. Đây là cách nó hoạt động:

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

Đây là chế độ nhanh có thể bỏ lỡ một số biểu tượng cảm xúc vì nó sử dụng thuật toán heuristic để tìm biểu tượng cảm xúc trong văn bản. Sử dụng .full()phương pháp để quét toàn bộ chuỗi và loại bỏ tất cả các biểu tượng cảm xúc được đảm bảo.


5
Câu hỏi là trong Java, do đó một plugin jQuery không liên quan ở đây.
riorio
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.