1. 程式人生 > >ASCII、Unicode和UTF-8編碼的區別;中英文混合擷取

ASCII、Unicode和UTF-8編碼的區別;中英文混合擷取

摘要總結:

ASCII編碼是128個字元

中國把漢字編入GB2312,Shift_JIS/Euc-kr各國標準.....

Unicode是為了解決各國亂碼的,但浪費儲存空間

UTF-8編碼把一個Unicode字元根據不同的數字大小編碼成1-6位元組,英文字母是1位元組,漢字通常是3位元組,生僻字元是4-6位元組


簡單歸納:

編碼 大小 支援語言
ASCII 1個位元組 英文
Unicode 2個位元組(生僻字4個) 所有語言
UTF-8 1-6個位元組,英文字母1個位元組,漢字3個位元組,生僻字4-6個位元組 所有語言
具體解釋:
最早只有127個字母被編碼到計算機裡,也就是大小寫英文字母、數字和一些符號,這個編碼表被稱為ASCII編碼,比如大寫字母A的編碼是65,小寫字母z的編碼是122。
但是要處理中文顯然一個位元組是不夠的,至少需要兩個位元組,而且還不能和ASCII編碼衝突,所以,中國製定了GB2312編碼,用來把中文編進去。
你可以想得到的是,全世界有上百種語言,日本把日文編到Shift_JIS裡,韓國把韓文編到Euc-kr裡,各國有各國的標準,就會不可避免地出現衝突,結果就是,在多語言混合的文字中,顯示出來會有亂碼。
因此,Unicode應運而生。Unicode把所有語言都統一到一套編碼裡,這樣就不會再有亂碼問題了。
Unicode標準也在不斷髮展,但最常用的是用兩個位元組表示一個字元(如果要用到非常偏僻的字元,就需要4個位元組)。現代作業系統和大多數程式語言都直接支援Unicode。
新的問題又出現了:如果統一成Unicode編碼,亂碼問題從此消失了。但是,如果你寫的文字基本上全部是英文的話,用Unicode編碼比ASCII編碼需要多一倍的儲存空間,在儲存和傳輸上就十分不划算。
所以,本著節約的精神,又出現了把Unicode編碼轉化為“可變長編碼”的UTF-8編碼。
UTF-8編碼把一個Unicode字元根據不同的數字大小編碼成1-6個位元組,常用的英文字母被編碼成1個位元組,漢字通常是3個位元組,只有很生僻的字元才會被編碼成4-6個位元組。如果你要傳輸的文字包含大量英文字元,用UTF-8編碼就能節省空間。
UTF-8編碼有一個額外的好處,就是ASCII編碼實際上可以被看成是UTF-8編碼的一部分,

所以,大量只支援ASCII編碼的歷史遺留軟體可以在UTF-8編碼下繼續工作。

理論解釋:

1、ASCII碼
在計算機內部,所有的資訊最終都表示為一個二進位制的字串。
一個位元組一共有256種不同的狀態,從0000000到11111111。
上世紀60年代,美國製定了一套字元編碼,對英語字元與二進位制位之間的關係,做了統一規定,稱為ASCII碼。
ASCII碼一共規定了128個字元的編碼。這128個符號,只佔用了一個位元組的後面7位,最前面的1位統一規定為0。
2、非ASCII編碼
擴充套件ASCII碼在保留原始的7位的基礎上,使用了最前的一位。
不同的國家有不同的字母,因此,哪怕它們都使用256個符號的編碼方式,代表的字母卻不一樣。
3、Unicode
正如上一節所說,世界上存在著多種編碼方式,同一個二進位制數字可以被解釋成不同的符號。
可以想象,如果有一種編碼,將世界上所有的符號都納入其中。
每一個符號都給予一個獨一無二的編碼,那麼亂碼問題就會消失。
這就是Unicode,就像它的名字都表示的,這是一種所有符號的編碼。
Unicode當然是一個很大的集合,現在的規模可以容納100多萬個符號。
每個符號的編碼都不一樣,比如,U+0639表示阿拉伯字母Ain,U+0041表示英語的大寫字母A,U+4E25表示漢字"嚴"。
Unicode只是一個符號集,它只規定了符號的二進位制程式碼,卻沒有規定這個二進位制程式碼應該如何儲存。
出現了兩個嚴重的問題,
第一個問題是,如何才能區別Unicode和ASCII?計算機怎麼知道三個位元組表示一個符號,而不是分別表示三個符號呢?
第二個問題是,英文字母只用一個位元組表示就夠了,如果Unicode統一規定,每個符號用三個或四個位元組表示,那麼每個英文字母前都必然有二到三個位元組是0,這對於儲存來說是極大的浪費,文字檔案的大小會因此大出二三倍。
4、UTF-8
UTF-8就是在網際網路上使用最廣的一種Unicode的實現方式。UTF-8是Unicode的實現方式之一。
UTF-8最大的一個特點,就是它是一種變長的編碼方式。
它可以使用1~4個位元組表示一個符號,根據不同的符號而變化位元組長度。
UTF-8的編碼規則很簡單,只有二條:
1)對於單位元組的符號,位元組的第一位設為0,後面7位為這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。
2)對於n位元組的符號(n>1),第一個位元組的前n位都設為1,第n+1位設為0,後面位元組的前兩位一律設為10。剩下的沒有提及的二進位制位,全部為這個符號的unicode碼。

5、Unicode與UTF-8之間的轉換
1)ANSI是預設的編碼方式。
    對於英文檔案是ASCII編碼,對於簡體中文檔案是GB2312編碼。(繁體中文版會採用Big5碼)
2)Unicode編碼指的是UCS-2編碼方式,即直接用兩個位元組存入字元的Unicode碼。little endian格式
3)Unicode big endian編碼格式
4)UTF-8編碼方式

首先我們要明確 UTF-8(8-bit Unicode Transformation Format)是在統一碼(Unicode)基礎上細化並優化後的一種長度可變的字元編碼方式,它是實現 Unicode 的方式之一,除了 UTF-8,還有UTF-16,UTF-32 等都可以實現 Unicode,但是 UTF-8 相對而言是用的最為廣泛的。
UTF-8 可以使用1到4個位元組來表示字元,它通過自身的規則能夠靈活地變化長度來儲存 Unicode 字元。
Unicode是兩個位元組嗎?
Unicode只是定義了一個龐大的、全球通用的字符集,併為每個字元規定了唯一確定的編號,具體儲存為什麼樣的位元組流,取決於字元編碼方案。推薦的Unicode編碼是UTF-16和UTF-8。




<?php

////////////////////////////////////////////////////////////////////
// PHP擷取中英文及標點符號混合的字串函式(絕對不會出現亂碼)
// 本程式在utf-8、gb2312中測試通過。使用者自行測試big5。
// 函式 left( 源字串, 擷取指定的字串個數, 編碼(可省略,預設為utf-8) )
////////////////////////////////////////////////////////////////////

function left($str, $len, $charset="utf-8")
{
    //如果擷取長度小於等於0,則返回空
    if( !is_numeric($len) or $len <= 0 )
    {
        return "";
    }

    //如果擷取長度大於總字串長度,則直接返回當前字串
    $sLen = strlen($str);
    if( $len >= $sLen )
    {
        return $str;
    }
 
    //判斷使用什麼編碼,預設為utf-8
    if ( strtolower($charset) == "utf-8" )
    {
        $len_step = 3; //如果是utf-8編碼,則中文字元長度為3  
    }else{
        $len_step = 2; //如果是gb2312或big5編碼,則中文字元長度為2
    } 

    //執行擷取操作
    $len_i = 0; 
    //初始化計數當前已擷取的字串個數,此值為字串的個數值(非位元組數)
    $substr_len = 0; //初始化應該要擷取的總位元組數

    for( $i=0; $i < $sLen; $i++ )
    {
        if ( $len_i >= $len ) break; //總擷取$len個字串後,停止迴圈
        //判斷,如果是中文字串,則當前總位元組數加上相應編碼的中文字元長度
        if( ord(substr($str,$i,1)) > 0xa0 )
        {
            $i += $len_step - 1;
            $substr_len += $len_step;
        }else{ //否則,為英文字元,加1個位元組
            $substr_len ++;
        }
        $len_i ++;
    }
    $result_str = substr($str,0,$substr_len );
    return $result_str;
}

////////////////////////////////////////////////////////////////////
// 呼叫示例
////////////////////////////////////////////////////////////////////
$str = "空格 也算一個字元"; 
echo "擷取後的字串:".left($str,14); 
//ord()是返回ASCII值;在ASCII中,0xa0表示漢字的開始
?>



參考連結1:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
                    https://my.oschina.net/darionyaphet/blog/221124
            http://blog.csdn.net/u012223913/article/details/51772610