Как я могу кодировать символы, такие как смайлики, как UTF8 без непарных суррогатных символов? - PullRequest
2 голосов
/ 16 апреля 2019

У меня есть строки с различными символами, которые необходимо записать в Google BigQuery, для которого требуются строгие строки UTF8.Когда я пытаюсь написать строки с большим количеством входных смайликов, я получаю сообщение об ошибке:

java.lang.IllegalArgumentException: Unpaired surrogate at index 3373
    at org.apache.beam.sdk.repackaged.com.google.common.base.Utf8.encodedLengthGeneral(Utf8.java:93)
    at org.apache.beam.sdk.repackaged.com.google.common.base.Utf8.encodedLength(Utf8.java:67)
    at org.apache.beam.sdk.coders.StringUtf8Coder.getEncodedElementByteSize(StringUtf8Coder.java:145)
...

У меня есть обходной путь для этой проблемы, чтобы просто убрать все суррогатные символы из строк:

    private static String removeSurrogates(String query) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < query.length(); i++) {
            char c = query.charAt(i);
            if (!(Character.isHighSurrogate(c) || Character.isLowSurrogate(c))) {
                sb.append(c);
            }
        }
        return sb.toString();
    }

Однако, это приводит к строке вроде

????????⚔⌨?⛳?????????????⛏?

Сокращение до четырех смайликов

⚔⌨⛳⛏

Есть ли правильный способ конвертировать эти символы в UTF8 без потерь и без использования непарных суррогатов?

(Извинениямоё понимание наборов символов в целом не велико)

Ответы [ 3 ]

2 голосов
/ 17 апреля 2019

Я нашел проблему. Мы используем org.apache.commons.lang3.StringEscapeUtils.unescapeHtml4 для преобразования сущностей HTML в строках в их некодированные формы. Кажется, это искажает некоторые нелатинские символы. Например, передача строки "Italien ??" через этот метод преобразует ее в "Italien ??" (последний персонаж изуродован)

Передача "????????⚔⌨?⛳?????????????⛏?" через этот метод преобразует его в "?? ?? ?? ?? ?? ?? ?? ?? ⚔⌨?? ⛳?? ?? ?? "

import org.apache.commons.lang3.StringEscapeUtils;

public class CharacterTest {
    public static void main(String[] args) {
        String good = "????????⚔⌨?⛳?????????????⛏?";
        String bad = StringEscapeUtils.unescapeHtml4(good);
        System.out.println(good + "->" + bad);
    }
}

????????⚔⌨?⛳?????????????⛏?->????????????????⚔⌨??⛳??????

Теперь, чтобы найти альтернативный декодер сущностей HTML ...

0 голосов
/ 16 апреля 2019

Позвольте мне на секунду выйти из Java, чтобы показать, что BigQuery может работать с emojis:

CREATE TABLE `public_dump.emoji_test`
AS
SELECT "????????⚔⌨?⛳?????????????⛏?" emojis

Затем проверить наличие:

SELECT COUNT(*)
FROM `fh-bigquery.public_dump.emoji_test`
WHERE emojis LIKE '%?%'

1

Выполнение этого с Pythonпросто:

enter image description here

Вставка новых данных также не является проблемой:

enter image description here

Извините, я не знаю, как это исправить с помощью Java, но я надеюсь, что это поможет увидеть это доказательство способности API BigQuery обрабатывать эмоджи с изяществом.

0 голосов
/ 16 апреля 2019

Is there a proper way to convert these characters into UTF8 Возможно, если вы просто отправите строку, она будет преобразована в UTF-8. Вот как работают кодеры Java.

Если это не так, и вы отправляете двоичный файл, вы можете просто преобразовать напрямую:

private static byte[] removeSurrogates(String query) {
    return query.getBytes( "UTF-8" );
}
...