如何在 Java 中查找不能存储在 MySQL“utf8”列中的字符

我使用 MySQL 5.7,我有一个表,其中有一列使用“utf8”字符集。不幸的是,它不是 utf8mb4,因此当我的应用程序尝试插入超出“utf8”(例如表情符号)范围的字符时,我总是会收到错误消息。


不幸的是,我不能很快将字符集更改为“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


一只甜甜圈
浏览 110回答 2
2回答

米琪卡哇伊

事实上,MySQLutf8在当时是正确的,因为 UTF-8 多字节序列最多只有 3 个字节。但是 Unicode 有更多的符号,UTF-8 也增长了。并且只能 utf8mb4做到。但是最多 3 个字节都可以:return input&nbsp; &nbsp; &nbsp; .codePoints()&nbsp; &nbsp; &nbsp; .filter(codePoint -> codePoint >= 256) // Optional heuristic optimisation&nbsp; &nbsp; &nbsp; .mapToObj(codePoint -> new String(Character.toChars(codePoint)))&nbsp; &nbsp; &nbsp; .filter(cpString -> cpString.getBytes(StandardCharsets.UTF_8).length > 3)&nbsp; &nbsp; &nbsp; .collect(Collectors.toSet())或者只是U+FFFF 以上的所有代码点:return input&nbsp; &nbsp; &nbsp; .codePoints()&nbsp; &nbsp; &nbsp; .filter(codePoint -> codePoint >= 0x1_0000)&nbsp; &nbsp; &nbsp; .mapToObj(codePoint -> new String(Character.toChars(codePoint)))&nbsp; &nbsp; &nbsp; .collect(Collectors.toSet());老实说,我需要研究是否Character.charCount(codePoint)也可以使用,因为它检查 UTF-16 中的代理项对,而不是 UTF-8 中的字节数。有用的可能是Character.getName(codePoint)将代码点替换为(如果字段有足够长的大小)。

梵蒂冈之花

如果 Java 中有一种方法可以生成 -encoded 字符串的十六进制表示,则在字符串中UTF-8搜索一个字节。F0如果 Java 中有一种方法可以生成编码字符串的 16 位表示UTF-16,则搜索包含D8xx-DFFF值的任何 16 位。(指出一些这样的方法,也许我可以详细说明。)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java