从 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 String
。 encode
的结果是一个 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();
}
我在网站上有一个文本区,用户可以在其中写任何东西。当用户复制粘贴一些包含非 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 String
。 encode
的结果是一个 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();
}