手機中文碼制問題的一點理解〔轉〕

來源:互聯網
上載者:User

作者:風過迴廊  來源:http://www.sf.org.cn

論壇上很多的文章都是在討論手機上的中文碼制問題,我也曾經被此類的問題所困擾,並且得到了不少熱心的朋友的協助。通過一端時間的資料尋找和測試學習,我對這個問題有一點點自己的理解和想法,不敢敝帚自珍,特分享給大家,由於本人水平有限,況且也是業餘的開發愛好者,沒有專業的理論學鰼水平,所以請大家就文章中的一些錯誤予以諒解並提出批評,本篇的文章僅做拋磚引玉,非常的歡迎大家的跟貼,我們群策群力,共同來解決這個問題。:)

論壇上很多的文章都是在討論手機上的中文碼制問題,我也曾經被此類的問題所困擾,並且得到了不少熱心的朋友的協助。通過一端時間的資料尋找和測試學習,我對這個問題有一點點自己的理解和想法,不敢敝帚自珍,特分享給大家,由於本人水平有限,況且也是業餘的開發愛好者,沒有專業的理論學鰼水平,所以請大家就文章中的一些錯誤予以諒解並提出批評,本篇的文章僅做拋磚引玉,非常的歡迎大家的跟貼,我們群策群力,共同來解決這個問題。:)

手機裡面的字串基本上都是採用的UTF-8的編碼法。
而我們在PC機器上所採用的基本上都是ASCII和unicode編碼法
ASCII編碼法是單位元組的編碼方法,只能表示256個字元,英文字母是足夠了
但是無法表示漢字
unicode是雙位元組的編碼法,可以用來表示漢字,但是卻對於一般的英文字母浪費了太多的空間(至少面對於手機的儲存是這樣的)。
UTF-8就是專門手機這種嵌入式裝置的新的編碼法,他的特點是,傳統的ASCII字元還是以一個位元組來表示的,但是如果字元不屬於ASCII字元集時,就用兩至三個位來表示。
  在 0x0001-0x007F之間的字元(傳統的ASCII字元)用一個位來表示
     0 | bits0-6
  在 0x000以及在0x0080-0x07FF之間的字元使用下面來表示:
     1 | 1 | 0 | bits 6-10 | 1 | 0 | bits 0-5
  如果虛擬機器看到這樣的一個字元的話,虛擬機器會把第一個位元組最前頭的110以及第二個位元組的前頭的10拿掉把剩下的位重新組合成一個2位元組的數位來表示字元:
     00000 | bits 6-10 | bits 0-5
  同理,0x0800 - 0xFFFF的字元表示:
 1 | 1 | 1 | 0 | bits 12-15 | 1 | 0 | bits 6-11 | 1 | 0 | bits  0-5  
  也可以用同樣的方法重新組合成一個兩個位元組的字串來  
  特別需要注意的是kjava中的null字元也使用兩個位元組來表示而不是一個位元組:)

當然英文字串在UTF-8編碼法中不會出什麼問題(預設為標準的ACSII編碼機制)主要的問題還是中文,我個人在Kjava的手機開發中中文字串所碰到的問題主要分為以下幾類:
 1.rms資料庫讀寫的問題;
 2.在jad中書寫遊戲中文名稱;
 3.網路傳輸中中文問題(kxml傳輸的解碼);
 4.部分的模擬器也不支援中文.
這幾個部分是在手機開發中,中文經常出錯的險區,通常的表現形式是亂碼:)

1.瞭解到了UTF-8碼的基本原理就非常的有利於我們解決碼制轉化的問題
在轉化UTF-8碼中我處理的方法是這樣的

//向資料庫中寫入中文
String appt3 = "中文字元";
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeUTF(appt3);
byte[] bytes3 = bos.toByteArray();
rs.addRecord(bytes3, 0, bytes3.length);

//從資料庫中讀出中文
byte b3[] = rs.getRecord(dbid);
DataInputStream dis=new DataInputStream(new ByteArrayInputStream(b3));
String chinastring = dis.readUTF();

writeUTF() 和 readUTF() 分別是DataOutputStream 和 DataInputStream對象的的方法,他們提供了一個由從Unicode到UTF-8的相互轉化的途徑。
仔細看看midp的說明文檔,可以看到以下內容
writeUTF() :
First, two bytes are written to the output stream as if by the writeShort method giving the number of bytes to follow. This value is the number of bytes actually written out, not the length of the string. Following the length, each character of the string is output, in sequence, using the UTF-8 encoding for the character.If no exception is thrown, the counter written is incremented by the total number of bytes written to the output stream. This will be at least two plus the length of str, and at most two plus thrice the length of str.

當然我們也可以自己來手工的編寫代碼,把中文字串轉化成byte[]再放入RMS,取出時轉成String即可。
這裡借用bingo_guan的方法(bingo_guan,請不要介意呀 :)),當然了這段代碼也非常的設計模式化 hehe,這個類也可用於文字檔操作。

/**
*

Title:

*

Description: unicode字串轉換工具

*

Copyright: Copyright (c) 2003

*

Company: CC Studio

* @author Bingo
* @version 1.0
*/

 

public class UnicodeString
{

public UnicodeString()
{
}

public static String byteArrayToString(byte abyte0[], int i)
{
StringBuffer stringbuffer = new StringBuffer("");
for(int j = 0; j < i; )
{
int k = abyte0[j++]; //注意在這個地方進行了碼制的轉換
if(k < 0)
k += 256;
int l = abyte0[j++];
if(l < 0)
l += 256;
char c = (char)(k + (l << 8));//把高位和低位元組裝起來
stringbuffer.append(c);
}

return stringbuffer.toString();
}

public static String byteArrayToString(byte abyte0[])
{
return byteArrayToString(abyte0, abyte0.length);
}

public static byte[] stringToByteArray(String s)
{
int i = s.length();
byte abyte0[] = new byte[i << 1];
int j = 0;
for(int k = 0; k < i; k++)
{
char c = s.charAt(k);
abyte0[j++] = (byte)(c & 0xff); //每一個位按位轉化
abyte0[j++] = (byte)(c >> 8);
}

return abyte0;
}
}

2.其次,在jad和manifest中的中文字(比如說遊戲的名字)實際上也都是 UTF-8編碼,這一塊也是經常出問題的險區,我建議還是自己手工轉化成UTF-8的編碼寫在上面,否則的話,如果你用unicode碼制寫入中文的話,在模擬器或者實際裝置上就有無法識別而導致程式不能執行的危險。所以大家在編輯jad檔案的時候應該盡量小心才好 特別注意,wtk的jad自動產生的工具並不支援直接在jad和manifest輸入UTF-8格式,所以手工修改這一步恐怕是免不了的了 :(。

3.不同的手機其實支援的預設碼制也是不一樣的,這也是經常出現問題的關鍵,CLDC的系統屬性"microedition.encoding"定義了裝置的預設字元編碼,它的值可以使用System.getProperty方法取得。我們也可以轉化成相關的支援的編碼機制來實際的運行我們的程式。
   這種方式我們通常會用在有關手機中文問題傳輸中,因為在連網時的手機是不確定的。以下我給出一段執行個體代碼,和大家探討一下這個問題。

伺服器到用戶端:
------------------------------------------------------------------
下面代碼是伺服器端把字元寫到Client端,經過gbEncoding()方法,所有的字元編碼成:/uXXXX.
-----------------------------------------------------------------

代碼:-------------------------------------------------------------
/**
* Write the String data
*
* @param out
* @param value
*/
public static void writeUnicode(final DataOutputStream out, final String value) throws ActionException {
try {
final String unicode = StringFormatter.gbEncoding( value );
final byte[] data = unicode.getBytes();
final int dataLength = data.length;

System.out.println( "Data Length is: " + dataLength );
System.out.println( "Data is: " + value );
out.writeInt( dataLength );       //先寫出字串的長度
out.write( data, 0, dataLength ); //然後寫出轉化後的字串
} catch (IOException e) {
throw new ActionException( IMDefaultAction.class.getName(), e.getMessage() );
}
}

----------------------------------------------------------------------
以下代碼是gbEncoding()方法,把雙位元組字元轉換成/uXXXX,ASIIC碼在前面補00。
----------------------------------------------------------------------
/**
* This method will encode the String to unicode.
*
* @param gbString
* @return
*/
 
代碼:--------------------------------------------------------------------------------
public static String gbEncoding( final String gbString ) {
char[] utfBytes = gbString.toCharArray();
String unicodeBytes = "";
for( int byteIndex = 0; byteIndex < utfBytes.length; byteIndex ++ ) {
String hexB = Integer.toHexString( utfBytes[ byteIndex ] );
if( hexB.length() <= 2 ) {
hexB = "00" + hexB;
}
unicodeBytes = unicodeBytes + //u}
System.out.println( "unicodeBytes is: " + unicodeBytes );
return unicodeBytes;
}
--------------------------------------------------------------------------------

----------------------------------------------------------------------
在用戶端收到伺服器的資料,先將其一個一個字元解碼。雙位元組顯示正常。
----------------------------------------------------------------------

代碼:--------------------------------------------------------------------------------
/**
* This method will decode the String to a recognized String
* in ui.
* @param dataStr
* @return
*/
private StringBuffer decodeUnicode( final String dataStr ) {
int start = 0;
int end = 0;
final StringBuffer buffer = new StringBuffer();
while( start > -1 ) {
end = dataStr.indexOf( "//u", start + 2 );
String charStr = "";
if( end == -1 ) {
charStr = dataStr.substring( start + 2, dataStr.length() );
} else {
charStr = dataStr.substring( start + 2, end);
}
char letter = (char) Integer.parseInt( charStr, 16 ); // 16進位parse整形字串。
buffer.append( new Character( letter ).toString() );
start = end;
}
return buffer;
}
--------------------------------------------------------------------------------

----------------------------------------------------------------------
用戶端到伺服器:
----------------------------------------------------------------------
用戶端使用下面方法把手機端的字元編碼成ISO-8859-1,傳給伺服器。
----------------------------------------------------------------------

代碼:--------------------------------------------------------------------------------
/**
* write the String data
* @param value
* @param outData
*/
private void writeSjis(DataOutputStream outData, String value) {
try {
byte[] data = null;
// data = ( value ).getBytes( "UTF-8" );
data = ( value ).getBytes( "ISO8859_1" );
outData.writeInt(data.length);
outData.write(data, 0, data.length);

System.out.println(" data.length: " + data.length);
System.out.println(" data.value: " + value);
} catch (Exception ex) {
System.out.println(" write error ");
ex.printStackTrace();
}
}
--------------------------------------------------------------------------------

----------------------------------------------------------------------
伺服器端收到用戶端字元流,是用下面方法將其轉為UTF-8,以後的操作都是基於UTF-8編碼。SQLServer可能會由於內嗎不通有不同的變換,所以存取資料庫是還要是具體的DB內碼作相應的處理。
----------------------------------------------------------------------

代碼:--------------------------------------------------------------------------------
/**
*
* @param iso
* @return
*/
public static String isoToUtf( final String iso ) {
String utfString = iso;
if( iso != null ) {
try {
utfString = new String( iso.getBytes( "ISO-8859-1" ), "UTF-8" );
} catch ( UnsupportedEncodingException e ) {
utfString = iso;
}
} else {
utfString = "";
}
return utfString;
}

只要手機支援unicode的gb2312編碼,應該都可以顯示正常。

4。至於某些手機的模擬器不支援中文(譬如nokia 60系列),那真的沒有辦法了,只有等待他的中文版本出來了 呵呵,:)

我的信箱是 zhaofei8009@wellhope.sh,非常的歡迎大家來信共同討論這個問題,也非常的希望交到技術上的朋友.

共同努力,一起進步!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.