我發現,凡事任何事情,都要留個心,否則的話,就是看完了,也會忘記,我以前看了個筆試題,當時就是涉及到中文字元串的問題,結果,我就直接把人家的答案和總結拿來看了,也沒去思考,結果,現在又碰到了這種問題,但是,我卻忘得一幹二淨。 假設n為要截取的位元組數。
p lic static void main(String[] args) throws Exception{ String str = " 愛中華abc 我愛傳智def'; String str = " 漢"; int num = trimGBK(str.getBytes("GBK"),5); System.out.println(str.s string(0,num) ); } p lic static int trimGBK(byte[] b,int n){ int num = 0; boolean bChineseFirstHalf = false; for(int i=0;i<n;i++) { if(b[i]<0 && !bChineseFirstHalf){ bChineseFirstHalf = tr; }else{ num++; bChineseFirstHalf = false; } } return num; } String string = "啊"; byte by[] = string.getBytes(); for(int i=0;i<by.length;i++) System.out.println(by[i]);
try { by = string.getBytes("utf8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } for(int i=0;i<by.length;i++) System.out.println(by[i]); try { by = string.getBytes("gb2312"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } for(int i=0;i<by.length;i++) System.out.println(by[i]); try { by = string.getBytes("iso-8859-1"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } for(int i=0;i<by.length;i++) System.out.println(by[i]); 輸出結果: -80 -95 * -27 -107 -118 * -80 -95 * 63 轉了一篇挺好的文章:關于Java編碼問題 Java的編碼問題挺煩的,以前總弄不清除,現在理了一下算是清晰一點。做個總結吧~
-
編碼問題的由來
這個問題網上資料很多的,這裡不多說了,推薦幾篇吧。Java編碼問題詳解,計算機編碼大全,轉:談談Unicode編碼,簡要解釋 S、UTF、BMP、BOM等名詞。說的還是比較清楚了。下面主要用程式說說。
-
String是什麼?
以前一直不清楚Java編碼轉來轉去轉的是啥。原來是因為不知道String是啥。在Java裡,一個String就是一串Unicode編碼的字元串。也就是說,Java在整個處理過程中,字元都是以Unicode編碼的。具體使用的是UTF-16也就是雙位元組的Unicode編碼。這就解釋了Java中為啥有個16bit的char類型。String就是由一個個char組成的。一個char中存的就是一個對應字元的Unicode編碼。
是以,Unicode在Java中成為一種“中間碼”,因為他覆寫了基本上所有的字元。而其他編碼的轉換都可以通過他來完成。
PS:話說回來,用雙位元組的話還是無法覆寫整個字元集的(因為有UTF-32),是以以前曾懷疑過char是否真是用來放Unicode字元的,隻有16的話以後擴充怎麼辦?現在确定了,擴充問題目前不用考慮。。。
-
轉什麼?怎麼轉?
這裡再說一個東西——byte。為啥說它?因為所有的轉來轉去都是在轉它。為啥轉它?因為他是字元編碼的最小機關。一個byte 是8bit,所有編碼方式都是由整數個byte組成的。是以,同一個String的不同編碼方式可以了解為同一個字元的不同byte數組表示而已。是以,自然而然我們就可以看到這樣的代碼了:
String S = “測試”
s.getBytes(“utf8″);
s.getBytes(“GB2312″);
s.getBytes(“GBK”);
通過這種方式就可以獲得任何編碼的byte數組。是以,在知道了一個byte[]數組,和它的編碼方式的情況下,我們就能獲得對應的String,是以有了下面的代碼:
byte[] b = *****;
String s = new String(b, “utf8″);
s = new String(b, “gb2312″);
通過上面可以看出,從String可以獲得任何編碼的byte數組,但是從byte數組到String就要小心了,必須知道對應的編碼方式才能進行。可以這麼說,byte數組告訴了我們這個字元的内容,而編碼方式告訴了我們如何去讀這個byte數組才能獲得我們需要的資訊。
-
什麼時候轉?
一句話——有IO的時候。編碼問題主要出現在檔案讀取,網絡傳輸等,可以說隻要有資訊傳遞的地方都存在這個問題。而在Java中,所有資訊的擷取(發送)已經被抽象為“流”的概念,是以,這就解釋了為什麼Java的IO中又加入了Reader和Writer。就是為了能讓上層直接面對你所需要的資訊,即:字元(char);同時,提供統一的接口解決編碼問題——想想看如果以上面String的形式來解決編碼問題将會是一件多麼可怕的事情~
一個sample:
p lic String dataReader(byte[] bytes, String charset) throws Exception {
Reader reader = new InputStreamReader(new ByteArrayInputStream(bytes), charset);
int c;
String result = “”
while( (c = reader.read()) != -1) {
result += (char)c;
}
reader.close();
return result;
} p lic byte[] dateWriter(String val, String charset) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
Writer writer = new OutputStreamWriter(out, charset);
char[] chars = val.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
writer.write(c);
}
writer.flush();
writer.close();
return out.toByteArray();
}
上面sample與前面的從String擷取byte數組和從byte數組生成String功能是一樣的。流的實作雖然複雜,但是因為流抽象,是以可以 很容易的替換為其他資料來源(如檔案,網絡等),而不用更改相關的處理代碼。
-
為什麼是“?”号
編碼轉換出問題時,最常見的是一個“?”。原因是當出現Java不認識的編碼時(即UTF-16不能編碼),則對應為一個“/ffd”,對應“?”号。此時再轉換為其他部分編碼時,則為“3F”。
-
神奇的“ISO-8859-1”
其實并不神奇,隻是有點特殊而已。此編碼隻針對單位元組(一個byte)進行編碼,是以編碼具有還原性。即不論何種編碼的byte數組,使用此編碼編碼後,再使用此編碼解碼,可以還原到原來的byte數組。這是其他編碼方式所不具備的。
- bit、byte、位、位元組、漢字、字元
-
- package com.suypower.chengyu.test;
- public class ByteTest {
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- byte b1 = 127;
- byte b2 = -128;
- byte b3 = 'a';
- byte b4 = 'A'; // 一個字母 = 1 byte = 8 bit
- // byte b5 ='aa'; 這就錯了
- // byte b6 ='中'; 這就錯了 一個漢字 2個位元組 16bit
- short s1 = '啊'; // 一個漢字 2個位元組 16bit short 是 16 bit位的
- // short s2 = '漢字'; // 2個漢字 4個位元組 32 bit int 是32 bit的
- // int i1 = '漢字'; 但是 int 是數字類型的 , char 是 16 bit的 = 2 byte = 一個漢字
- char c1 = '汗';
- // byte 轉換 string
- String string = "中文";
- byte by[] = string.getBytes();
- String str = new String(by);
- System.out.println("str="+str);
- }
- }
- ==================================================================================
- [Java-原創] bit、byte、位、位元組、漢字、字元
- bit、byte、位、位元組、漢字的關系
- 1 bit = 1 二進制資料
- 1 byte = 8 bit
- 1 字母 = 1 byte = 8 bit
- 1 漢字 = 2 byte = 16 bit
- 1. bit:位
- 一個二進制資料0或1,是1bit;
- 2. byte:位元組
- 存儲空間的基本計量機關,如:MySQL中定義 VARCHAR(45) 即是指 45個位元組;
- 1 byte = 8 bit
- 3. 一個英文字元占一個位元組;
- 1 字母 = 1 byte = 8 bit
- 4. 一個漢字占2個位元組;
- 1 漢字 = 2 byte = 16 bit
- 5. 标點符号
- A>. 漢字輸入狀态下,預設為全角輸入方式;
- B>. 英文輸入狀态下,預設為半角輸入方式;
- C>. 全角輸入方式下,标點符号占2位元組;
- D>. 半角輸入方式下,标點符号占1位元組;
- 故:漢字輸入狀态下的字元,占2個位元組 (但不排除,自己更改了預設設定);
- 英文輸入狀态下的字元,占1個位元組 (但不排除,自己更改了預設設定);
- 本内容來源與網絡,具體位址不詳。