1. 程式人生 > >Java按位元組數擷取字串(防止中文被截成一半)

Java按位元組數擷取字串(防止中文被截成一半)

Web應用程式在瀏覽器中顯示字串時,由於顯示長度的限制,常常需要將字串擷取後再進行顯示。

但目前很多流行的語言,如C#、Java內部採用的都是 Unicode 16(UCS2)編碼,在這種編碼中所有的字元都是兩個字元,因此,如果要擷取的字串是中、英文、數字混合的,就會產生問題,如下面的字串:

String s = "a加b等於c,如果a等1、b等於2,那麼c等3";

上面的字串既有漢字,又有英文字元和數字。如果要擷取前6個位元組的字元,應該是”a加b等",但如果用substring方法擷取前6個字元就成了"a 加b等於c"。

產生這個問題的原因是將substring方法將雙位元組的漢字當成一個位元組的字元(UCS2字元)處理了。要解決這個問題的方法是首先得到該字串的UCS2編碼的位元組陣列,如下面的程式碼如下:

byte[] bytes = s.getBytes("Unicode");

由於上面生成的位元組陣列中前兩個位元組是標誌位,bytes[0] = -2,bytes[1] = -1,因此,要從第三個位元組開始掃描,對於一個英文或數字字元,UCS2編碼的第二個位元組是相應的ASCII,第一個位元組是0,如a的UCS2編碼是0  97,而漢字兩個位元組都不為0,因此,可以利於UCS2編碼的這個規則來計算實際的位元組數,該方法的實現程式碼如下:

package com.test.common.util;

import java.io.UnsupportedEncodingException;

public class StringUtil {

	/**
	 * 按照指定位元組長度擷取字串,防止中文被截成一半的問題
	 * @param s 源字串
	 * @param length 擷取的位元組數
	 * @return 擷取後的字串
	 * @throws UnsupportedEncodingException 
	 */
	public static String cutString(String s, int length) throws UnsupportedEncodingException{
		
		byte[] bytes = s.getBytes("Unicode");
        int n = 0; // 表示當前的位元組數
        int i = 2; // 要擷取的位元組數,從第3個位元組開始
        for (; i < bytes.length && n < length; i++){
            // 奇數位置,如3、5、7等,為UCS2編碼中兩個位元組的第二個位元組
            if (i % 2 == 1){
                n++; // 在UCS2第二個位元組時n加1
            }
            else{
                // 當UCS2編碼的第一個位元組不等於0時,該UCS2字元為漢字,一個漢字算兩個位元組
                if (bytes[i] != 0){
                    n++;
                }
            }
        }
        // 如果i為奇數時,處理成偶數
        if (i % 2 == 1){
            // 該UCS2字元是漢字時,去掉這個截一半的漢字
            if (bytes[i - 1] != 0){
                i = i - 1;
            }
            // 該UCS2字元是字母或數字,則保留該字元
            else{
                i = i + 1;
            }
        }

        return new String(bytes, 0, i, "Unicode");
        
	}
	
	public static void main(String[] args) throws UnsupportedEncodingException{
		String s = "a加b等於c,如果a等1、b等於2,那麼c等3";
		System.out.println(cutString(s, 6));	//測試結果為:a加b等
		System.out.println(s.substring(0, 6));	//測試結果為:a加b等於c
	}
	
}