从 String 中删除不适合 UTF-8 编码的字符

Remove characters not-suitable for UTF-8 encoding from String

我在网站上有一个文本区,用户可以在其中写任何东西。当用户复制粘贴一些包含非 UTF 8 字符的文本或内容并将它们提交到服务器时,会出现问题。

Java 成功处理它,因为它支持 UTF-16,但我的 mySql table 支持 UTF-8,因此插入失败。

我试图在业务逻辑本身中实现某种方式,以删除任何不适合 UTF-8 编码的 table 字符。

目前我正在使用这个代码:

new String(java.nio.charset.Charset.forName("UTF-8").encode(myString).array());

但它用其他一些晦涩的字符替换了 UTF-8 不符合 table 的字符。这对最终用户来说也不好看。有人可以使用 Java 代码阐明任何可能的解决方案来解决这个问题吗?

编辑: 例如,插入此类值时出现异常

java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x8A\x0D\x0A...' for column

java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x80\xF0\x9F...' for column

UTF-8不是字符集,是字符编码,和UTF-16一样

UTF-8 能够将任何 unicode 字符和任何 unicode 文本编码为字节序列,因此不存在不适合 UTF-8 的字符。

您正在使用 String 的构造函数,它只接受一个字节数组 (String(byte[] bytes)),根据 javadocs:

Constructs a new String by decoding the specified array of bytes using the platform's default charset.

它使用平台的默认字符集来解释字节(将字节转换为字符)。不要使用这个。相反,当将字节数组转换为 String 时,请指定您希望使用 String(byte[] bytes, Charset charset) 构造函数显式使用的编码。

如果您对某些字符有问题,这很可能是由于在服务器端和客户端使用不同的字符集或编码 (brownser+HTML)。确保在任何地方都使用 UTF-8,不要混合编码,也不要使用平台的默认编码。

一些阅读材料如何实现:

How to get UTF-8 working in Java webapps?

您的代码中的问题是您在 byte[] 上调用 new Stringencode 的结果是一个 ByteBuffer,array 在 ByteBuffer 上的结果是一个 byte[]。 构造函数 new String(byte[]) 将使用您计算机的平台默认编码;它在您 运行 所在的每台计算机上可能不同,因此这不是您想要的。 您至少应该将一个字符集作为第二个参数传递给 String 构造函数,尽管我不确定您会想到哪个字符集。

我不确定您为什么要这样做:如果您的数据库使用 UTF-8,它会为您进行编码。您只需要将未编码的字符串传递给它即可。

UTF-8和UTF-16都可以编码整个Unicode 6字符集;没有可以用 UTF-16 编码但不能用 UTF-8 编码的字符。所以很遗憾,你的那部分问题无法回答。

一些背景:

也许 CharsetDecoder of this question helps. You could change the CodingErrorAction to REPLACE and set a replacement in my example "?". This will output a given replacement string for invalid byte sequences. In this example a UTF-8 decoder capability and stress test file 的答案被读取和解码:

CharsetDecoder utf8Decoder = Charset.forName("UTF-8").newDecoder();
utf8Decoder.onMalformedInput(CodingErrorAction.REPLACE);
utf8Decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
utf8Decoder.replaceWith("?");

// Read stress file
Path path = Paths.get("<path>/UTF-8-test.txt");
byte[] data = Files.readAllBytes(path);
ByteBuffer input = ByteBuffer.wrap(data);

// UTF-8 decoding
CharBuffer output = utf8Decoder.decode(input);

// Char buffer to string
String outputString = output.toString();

System.out.println(outputString);

我想这可能对你有用 Easy way to remove UTF-8 accents from a string?

尝试使用 Normalizer 作为,

s = Normalizer.normalize(s, Normalizer.Form.NFD);

如果 MySQL 列使用旧的 utf8 编码,每个字符仅使用 3 个字节,并且该值包含一个 4 字节字符,那么您将 运行 遇到此问题。

实际的解决方案是在MySQL中使用utf8mb4而不是utf8

否则这是我删除所有 4 字节字符的肮脏解决方法:

public String removeUtf8Mb4(String text) {
    StringBuilder result = new StringBuilder();
    StringTokenizer st = new StringTokenizer(text, text, true);
    while (st.hasMoreTokens()) {
        String current = st.nextToken();
        if(current.getBytes().length <= 3){
            result.append(current);
        }
    }
    return result.toString();
}