簡體   English   中英

從字符串中刪除不適合 UTF-8 編碼的字符

[英]Remove characters not-suitable for UTF-8 encoding from String

我在網站上有一個文本區域,用戶可以在其中編寫任何內容。 當用戶復制粘貼一些文本或包含非 UTF 8 字符的內容並將它們提交到服務器時會發生問題。

Java 成功地處理了它,因為它支持 UTF-16,但我的 mySql 表支持 UTF-8,因此插入失敗。

我試圖在業務邏輯本身中實現某種方式,以刪除任何不適合 UTF-8 編碼的字符。

目前我正在使用此代碼:

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

但它用其他一些晦澀的字符替換了不適合 UTF-8 的字符。 這對最終用戶來說也不好看。 有人可以介紹一下使用 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 :

通過使用平台的默認 charset解碼指定的字節數組來構造一個新的 String 。

它使用平台的默認字符集來解釋字節(將字節轉換為字符)。 不要使用這個。 相反,在將字節數組轉換為String ,請使用String(byte[] bytes, Charset charset)構造函數指定您希望顯式使用的編碼。

如果您對某些字符有問題,這很可能是由於在服務器端和客戶端(瀏覽器 + HTML)使用了不同的字符集或編碼。 確保在任何地方都使用 UTF-8,不要混合編碼,也不要使用平台的默認編碼。

一些閱讀如何實現這一目標:

如何讓 UTF-8 在 Java webapps 中工作?

也許這個問題CharsetDecoder的答案有幫助。 您可以將CodingErrorAction更改為 REPLACE 並在我的示例“?”中設置替換。 這將為無效字節序列輸出給定的替換字符串。 在此示例中,讀取並解碼了UTF-8 解碼器功能和壓力測試文件

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);

您的代碼中的問題是您在byte[]上調用new String encode的結果是一個 ByteBuffer,一個 ByteBuffer 上的array的結果是一個byte[] 構造函數new String(byte[])將使用您計算機的平台默認編碼; 它在您運行的每台計算機上都可能不同,因此這不是您想要的。 您至少應該將字符集作為第二個參數傳遞給 String 構造函數,盡管我不確定您會想到哪個字符集。

我不確定您為什么要這樣做:如果您的數據庫使用 UTF-8,它將為您進行編碼。 您只需要將未編碼的字符串傳遞給它。

UTF-8 和 UTF-16 都可以編碼整個 Unicode 6 字符集; 沒有可以由 UTF-16 編碼但不能由 UTF-8 編碼的字符。 因此,不幸的是,您問題的那部分無法回答。

對於一些背景:

我認為這可能對您有用從字符串中刪除 UTF-8 重音的簡單方法?

嘗試使用 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();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM