Удаление символов определенного диапазона юникода из строки

У меня есть программа, которая разворачивает твиты в реальном времени из потока twitter api. Прежде чем хранить их, я кодирую их как utf8. Некоторые символы попадают в строку как?,?? или??? вместо их соответствующих кодов Юникода и вызывают проблемы. При дальнейших исследованиях я обнаружил, что проблемные символы взяты из "смайлика" блока, U + 1F600 - U + 1F64F и "Разное Блок символов и пиктограмм, U + 1F300 - U + 1F5FF. Я попытался удалить, но не был успешным, так как совпадчик заменил почти каждый символ в строке, а не только нужный диапазон юникода.

String utf8tweet = "";
        try {
            byte[] utf8Bytes = status.getText().getBytes("UTF-8");

            utf8tweet = new String(utf8Bytes, "UTF-8");

        } 
        catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
Pattern unicodeOutliers = Pattern.compile("[\\u1f300-\\u1f64f]", Pattern.UNICODE_CASE | Pattern.CANON_EQ | Pattern.CASE_INSENSITIVE);
Matcher unicodeOutlierMatcher = unicodeOutliers.matcher(utf8tweet);
utf8tweet = unicodeOutlierMatcher.replaceAll(" ");

Что я могу сделать, чтобы удалить эти символы?

Ответы

Ответ 1

В шаблоне регулярного выражения добавьте оператор отрицания ^. Для фильтрации печатных символов вы можете использовать следующее выражение [^\\x00-\\x7F], и вы должны получить желаемый результат.

import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UTF8 {
    public static void main(String[] args) {
        String utf8tweet = "";
        try {
            byte[] utf8Bytes = "#Hello twitter  How are you?".getBytes("UTF-8");

            utf8tweet = new String(utf8Bytes, "UTF-8");

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        Pattern unicodeOutliers = Pattern.compile("[^\\x00-\\x7F]",
                Pattern.UNICODE_CASE | Pattern.CANON_EQ
                        | Pattern.CASE_INSENSITIVE);
        Matcher unicodeOutlierMatcher = unicodeOutliers.matcher(utf8tweet);

        System.out.println("Before: " + utf8tweet);
        utf8tweet = unicodeOutlierMatcher.replaceAll(" ");
        System.out.println("After: " + utf8tweet);
    }
}

Результаты в следующем выпуске:

Before: #Hello twitter  How are you?
After: #Hello twitter   How are you?

ИЗМЕНИТЬ

Чтобы пояснить далее, вы могли бы также выразить диапазон с формой \u следующим образом [^\\u0000-\\u007F], который будет соответствовать всем символам, которые не являются первыми 128 символами UNICODE (такими же, как и раньше). Если вы хотите расширить диапазон для поддержки дополнительных символов, вы можете сделать это, используя список символов UNICODE здесь.

Например, если вы хотите включить гласные с акцентом (используется на испанском языке), вы должны расширить диапазон до \u00FF, поэтому у вас есть [^\\u0000-\\u00FF] или [^\\x00-\\xFF]:

Before: #Hello twitter  How are you? á é í ó ú
After: #Hello twitter   How are you? á é í ó ú

Ответ 2

Прежде всего, соответствующий блок unicode указан в java (строго следуя стандарту) как Character.UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS. В регулярном выражении:

s = s.replaceAll("\\p{So}+", "");

Ответ 3

Я пробовал это. Диапазоны Unicode относятся к диапазонам emoji

    class EmojiEraser{

    private static final String EMOJI_RANGE_REGEX =
                "[\uD83C\uDF00-\uD83D\uDDFF]|[\uD83D\uDE00-\uD83D\uDE4F]|[\uD83D\uDE80-\uD83D\uDEFF]|[\u2600-\u26FF]|[\u2700-\u27BF]";
        private static final Pattern PATTERN = Pattern.compile(EMOJI_RANGE_REGEX);

        /**
         * Finds and removes emojies from @param input
         * 
         * @param input the input string potentially containing emojis (comes as unicode stringfied)
         * @return input string with emojis replaced
         */
        public String eraseEmojis(String input) {
            if (Strings.isNullOrEmpty(input)) {
                return input;
            }
            Matcher matcher = PATTERN.matcher(input);
            StringBuffer sb = new StringBuffer();
            while (matcher.find()) {
                matcher.appendReplacement(sb, "");
            }
            matcher.appendTail(sb);
            return sb.toString();
        }
}

Ответ 4

Предполагая, что status.getText() возвращает a java.lang.String...

byte[] utf8Bytes = status.getText().getBytes("UTF-8");
utf8tweet = new String(utf8Bytes, "UTF-8");

Вышеуказанная операция транскодирования дает те же результаты, что и:

utf8tweet = status.getText();

Строки Java неявно UTF-16. UTF-16 и UTF-8 используют один и тот же набор символов (Unicode), поэтому преобразование из одного в другое и обратно приводит к исходным данным.

Регулярные выражения Java поддерживают дополнительный диапазон, используя суррогатные пары. Вы можете сопоставить их, как описано в ответах на этот вопрос.

Как отмечает eee в своем комментарии, у вас, скорее всего, есть проблема с шрифтом. Независимо от того, отображается ли графема, обычно зависит от шрифтов, доступных в пользовательской системе, выбранного шрифта и какой формы подстановки шрифтов поддерживает технология рендеринга.