Как найти символ, который не может быть сохранен в колонке MySQL «utf8» в Java - PullRequest
0 голосов
/ 28 июня 2019

Я использую MySQL 5.7, и у меня есть таблица, в которой есть столбец, который использует набор символов «utf8».К сожалению, это не utf8mb4, поэтому я всегда получаю сообщение об ошибке, когда мое приложение пытается вставить символ, выходящий за пределы диапазона «utf8» (например, emojis).

К сожалению, я не могу изменить набор символовна «utf8mb4» в ближайшее время, поэтому мне интересно, возможно ли обнаружить те символы, которые вызывают ошибку до того, как она вставлена ​​в таблицу, и сообщить нашим клиентам, что они не могут их использовать.

Я где-то читалчто все, что находится за пределами диапазона от U + 0000 до U + FFFF, приводит к возникновению ошибки.Мое приложение реализовано на Java 8. Итак, мой вопрос: как мне написать код, который может найти такие проблемные символы в экземпляре String? следующий код делает то, что я хочу?

import java.util.Set;
import java.util.stream.Collectors;

class Utf8Mb3Validator {

    /**
     * finds characters which can’t be stored in a MySQL “utf8” column out of a given String.
     *
     * @param input a String which you want to check
     * @return a Set which contains strings that can't be inserted into MySQL "utf8" columns
     */
    Set<String> findProblematicStrings(String input) {
        // References:
        // https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-utf8mb3.html
        // https://www.oracle.com/technetwork/java/javase/downloads/supplementary-142654.html?printOnly=1
        // https://stackoverflow.com/q/56800767/3591946
        return input
                .codePoints() // get Unicode code points
                .filter(codePoint -> Character.charCount(codePoint) > 1) // search for non-BMP characters
                .mapToObj(codePoint -> new String(Character.toChars(codePoint))) // convert code points into Strings
                .collect(Collectors.toSet());
    }
}

Я также разместил этот вопрос на форуме MySQL: https://forums.mysql.com/read.php?39,675862,675862#msg-675862

Ответы [ 2 ]

1 голос
/ 29 июня 2019

Действительно, utf8 в MySQL в то время был верным, поскольку многобайтовые последовательности UTF-8 имели не более 3 байтов. Но Unicode получил больше символов, и UTF-8 тоже вырос. И только utf8mb4 может сделать.

Однако до 3 байтов все в порядке:

return input
      .codePoints()
      .filter(codePoint -> codePoint >= 256) // Optional heuristic optimisation
      .mapToObj(codePoint -> new String(Character.toChars(codePoint)))
      .filter(cpString -> cpString.getBytes(StandardCharsets.UTF_8).length > 3)
      .collect(Collectors.toSet())

Или просто все кодовые точки выше U + FFFF :

return input
      .codePoints()
      .filter(codePoint -> codePoint >= 0x1_0000)
      .mapToObj(codePoint -> new String(Character.toChars(codePoint)))
      .collect(Collectors.toSet());

Честно признаюсь, мне нужно было бы исследовать, можно ли также использовать Character.charCount(codePoint), поскольку он проверяет суррогатные пары в UTF-16, а не количество байтов в UTF-8.

Может быть полезно Character.getName(codePoint) для замены кодовой точки (если поля имеют достаточно длинный размер).

0 голосов
/ 28 июня 2019

Если в Java существует метод для получения шестнадцатеричного представления строки, закодированной в UTF-8, то ищите байт F0 в строке.

Если в Java есть метод длясоздайте 16-битные представления строки, кодированной UTF-16, затем найдите любой 16-битный код, содержащий значение D8xx-DFFF.

(укажите на некоторые из таких методов, и, возможно, я смогу уточнить).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...