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 = System.Text.Encoding.Unicode.GetBytes(s);
然後從第一個位元組開始掃描,對於一個英文或數字字元,UCS2編碼的第一個位元組是相應的ASCII,第二個位元組是0,如a的UCS2編碼是97 0,而漢字兩個位元組都不為0,因此,可以利於UCS2編碼的這個規則來計算實際的位元組數,為了更方便,將按位元組長度截取字串的方法註冊為String類的擴充方法,實現代碼如下:
public static class StringExt
{
public static String bSubstring(this string s, int length)
{
byte[] bytes = System.Text.Encoding.Unicode.GetBytes(s);
int n = 0; // 表示當前的位元組數
int i = 0; // 要截取的位元組數
for (; i < bytes.GetLength(0) && n < length; i++)
{
// 偶數位置,如0、2、4等,為UCS2編碼中兩個位元組的第一個位元組
if (i % 2 == 0)
{
n++; // 在UCS2第一個位元組時n加1
}
else
{
// 當UCS2編碼的第二個位元組大於0時,該UCS2字元為漢字,一個漢字算兩個位元組
if (bytes[i] > 0)
{
n++;
}
}
}
// 如果i為奇數時,處理成偶數
if (i % 2 == 1)
{
// 該UCS2字元是漢字時,去掉這個截一半的漢字
if (bytes[i] > 0)
i = i - 1;
// 該UCS2字元是字母或數字,則保留該字元
else
i = i + 1;
}
return System.Text.Encoding.Unicode.GetString(bytes, 0, i);
}
}
在上面的代碼中,如果最後要截取奇數個字元(以位元組為單位),並且當最後一個字元是字母或數字,則保留該字元,如果是漢字,說明這個漢字被截了一半,則去掉這個漢字。
可以使用下面的代碼來截取字串:
String subStr = s.bSubstring(6); // substr的值是"a加b等"