1. 程式人生 > >位(bit)、位元組(byte)、字元、編碼之間的關係

位(bit)、位元組(byte)、字元、編碼之間的關係

1、位:

     資料儲存的最小單位。每個二進位制數字0或者1就是1個位;

2、位元組:

     8個位構成一個位元組;即:1 byte (位元組)= 8 bit(位);

     1 KB = 1024 B(位元組);

     1 MB = 1024 KB;   (2^10 B)

     1 GB = 1024 MB;  (2^20 B)

     1 TB = 1024 GB;   (2^30 B)

3、字元:

     a、A、中、+、*、の......均表示一個字元;

     一般 utf-8 編碼下,一個漢字 字元 佔用 3 個 位元組;

     一般 gbk 編碼下,一個漢字  字元  佔用 2 個 位元組;

4、字符集:

     即各種各個字元的集合,也就是說哪些漢字,字母(A、b、c)和符號(空格、引號..)會被收入標準中;

5、編碼:

     規定每個“字元”分別用一個位元組還是多個位元組儲存,用哪些位元組來儲存,這個規定就叫做“編碼”。(其實際是對字符集中字元進行編碼,即:每個字元用二進位制在計算中表示儲存);

    通俗的說:編碼就是按照規則對字元進行翻譯成對應的二進位制數,在計算器中執行儲存,使用者看的時候(比如瀏覽器),在用對應的編碼解析出來使用者能看懂的;

    (1)標準ASCii字符集:有96個列印字元,和32個控制字元組成;一共96+32=128個;

             用7位二進位制數來對每1個字元進行編碼;

             而由於7位還還不夠1個位元組,而電腦的內部常用位元組來用處理,每個位元組中多出來的最高位用0替代;

             0 000   0000.........................0

             0 111    1111..........................127;   從0----127,來表示128個ACSii編碼;

             比如:字元 'A'----------在計算器內部用0100 0001 (65)來表示;

                        字元'a'-----------在計算器內部用110 0001 (97)來表示;

             注意:'10'在計算器內部是沒有編碼的,因為它是字串,而不是單個字元。可以分別對1,0字元編碼儲存;

     (2)擴充套件ASCii字符集:將標準的ASCii最高位1得到十進位制程式碼128---255(1 000 0000----1 111 1111);所以字符集一共有0---255,  256個字元;

      (3)gb2312字符集: 所有漢字字元在計算機內部採用2個位元組來表示,每個位元組的最高位規定為1【正好與標準ASCii字元(最高位是0)不重疊,併兼容】,不支援繁體字;

             所以:gb2312表示漢字的編碼為:[129--255][129--255]  (兩個位元組,每個位元組最高位是1);小於127的字元,與ASCii編碼相同;

      (4)gbk字符集:gb2312的擴充,相容gb2312,除了收錄gb2312所有的字元外,還收錄了其他不常見的漢字、繁體字等;

             gbk中字元是一個或兩個位元組,單位元組字元00--7F(0---127)這個區間和ASCII是一樣的;

             雙位元組字元的第一個位元組是在81--FE(129--254)之間。通過這個可以判斷是單位元組還是雙位元組;

                   即:在gbk字元編碼,如果第一個位元組是>128的,則再往後找一個位元組,組成漢字;如果第一個位元組<128,則表示的是一個單位元組(此時和ASCII是一樣的);

<?php
// gbk編碼下,無亂碼擷取中文字元;

// 方法1:自定義函式1;

function subgbk($str,$lens){  // 形參 $str 表示將要擷取的原始字串, $lens 表示 設定需要擷取的 字元 個數;
	
	if($lens<=0){
		
		return '';
	}
	
	$chars = 0;   // 計算,統計已經擷取的字元個數;
	$res = '';    //  已經擷取的字元長度;
    $offset = 0;  // 偏移量,從字串中那個位元組開始擷取;
	
	$lengths = strlen($str);    // 將要擷取的原始字串 位元組 的數;
    while($chars<$lens && $offset<$lengths){
		
		$hight = ord(substr($str,$offset,1));  // 計算出 gbk字元中 高位元組的所對應編碼的值;
		
		
		
		if($hight>128){
			
			// 擷取兩個位元組,代表一個字元;即:雙位元組字元;
			$count = 2;
		}else{
			
			//擷取一個位元組,代表一個字元,即:單位元組字元;
			$count = 1;
		}
		
		$res .= substr($str,$offset,$count);
		$offset += $count;
		$chars++;
	}	
	
	return $res;
}
?>


<?php

// 方法2:自定義函式2;

// 思路:先把字串中 所有的 字元 逐一取出來  組成陣列,然後對 陣列元素 進行擷取;最後截取出的陣列拼接成想要的字串;

function strgbk2($str,$strat,$length=NULL){   // 第三個引數預設設定的值是NULL,這個引數是參考了下邊的array_slice()函式,如果省略的話,則表示,一直擷取到最後末尾;
	
	$zijielen = strlen($str);    //  計算出 原始字串 $str 的 位元組長度;
	
	$chars = 0;     // 統計計算擷取的 字元 數;
	
	$zifuarr = array();  //將字串按照 字元 的形式 分割到 陣列中;(待儲存);	
	
	for($i = 0;$i<$zijielen;){  // $i 表示 原始字串 $str 中的位元組(標記); 
		
		if(ord(substr($str,$i,1)) > 128){
			// 雙位元組字元,兩個位元組來表示一個字元;
			
			$zifuarr[] = $str[$i].$str[$i+1];
		//	$zifuarr[] = substr($str,$i,2);    兩種寫法的意思是一樣的,都是 取得 某個字元 某些的 位元組;
			$i += 2;
		}else{
			//  單位元組字元,一個位元組表示一個字元;
			
			$zifuarr[] = $str[$i];
		//	$zifuarr[] = substr($str,$i,1);	兩種寫法的意思是一樣的,都是 取得 某個字元 某個的 位元組;
			$i++;
		}
		
	   $chars++;        // 每次迴圈,相當於擷取一個儲存 字元;  相當於所有的陣列元素個數 count($zifuarr);
	}
		
	if($chars < $strat){    //  當偏移 過 字元 總長度時候;(開始擷取的位置,已經超過了字元的總長度);
		return 'No characters have been found !';
	}
	
	return implode(array_slice($zifuarr,$strat,$length));  // array_slice()是擷取陣列一部分;implode()是將截取出來的字串,連結起來;
    
}

?>

<?php

// 方法3:用php內建的函式 mb_substr擷取;

//此函式和 mb_strlen()函式一樣,都是針對 多位元組 字元 的操作函式,在特定的編碼下,針對 字元 的 擷取(mb_substr)和長度的計算(mb_strlen);

$strgbk = 'ds我是fdg一箇中國xghdt人';
echo mb_substr($strgbk,2,3,'gbk');  // 我是f

?>


     (5)Unicode字符集:容納世界上所有語言字元和符號的集合;(以及對應的二進位制數字);

    Unicode只是一個編碼規範,目前實際實現的unicode編碼只要有三種:UTF-8,UCS-2和UTF-16,三種unicode字符集之間可以按照規範進行轉換。

     (6)utf-8編碼:UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字元編碼,也是一種字首碼。它可以用來表示Unicode標準中的任何字元,且其編碼中的第一個位元組仍與ASCII兼容,這使得原來處理ASCII字元的軟體無須或只須做少部分修改,即可繼續使用。因此,它逐漸成為電子郵件、網頁及其他儲存或傳送文字的應用中,優先採用的編碼。


對於UTF-8編碼中的任意位元組B,如果B的第一位為0,則B獨立的表示一個字元(ASCII碼);

如果B的第一位為1,第二位為0,則B為一個多位元組字元中的一個位元組(非ASCII字元);

如果B的前兩位為1,第三位為0,則B為兩個位元組表示的字元中的第一個位元組;

如果B的前三位為1,第四位為0,則B為三個位元組表示的字元中的第一個位元組;

如果B的前四位為1,第五位為0,則B為四個位元組表示的字元中的第一個位元組;

因此,對UTF-8編碼中的任意位元組,根據第一位,可判斷是否為ASCII字元;根據前二位,可判斷該位元組是否為一個字元編碼的第一個位元組;根據前四位(如果前兩位均為1),可確定該位元組為字元編碼的第一個位元組,並且可判斷對應的字元由幾個位元組表示;根據前五位(如果前四位為1),可判斷編碼是否有錯誤或資料傳輸過程中是否有錯誤。

即:
1、單位元組的字元,位元組的第一位設為0,對於英語文字,UTF-8碼只佔用一個位元組,和ASCII碼完全相同;
2、n個位元組的字元(n>1),第一位元組的前n位設為1,第n+1位設為0,後面位元組的前兩位都設為10;

3、2個位元組,第一個位元組的前2位是1;3個位元組,第一個位元組的前三位是1; 4個位元組,第一個位元組的前4位都是1;

// 如何擷取中文,無亂碼,假設utf-8編碼;

<?php
       
	// 方法1:自定義函式;   

function subutf8($str,$len){  // 兩個形式引數,$str代表原始目標字串,$len表示需要擷取 字元 的個數;   注意是 字元的 個數;
        
		if($len<=0){     // 當 將要擷取的字元數 <=0的時候 返回 空字串;
			
			return '';
		}
		
		
		$chars = 0 ;                                // $chars 引數 代表 已經擷取的字元的個數, 預設初始設定為0;
		$res = '';                                  // $res 引數 表示  已經擷取的字串的長度, 預設初始設定為空(字串);
		$offset = 0;                                // $offset 引數 表示 位元組 擷取的偏移量; 即從字串中(偏移幾個位元組)哪個位元組開始擷取; 
		$lengths = strlen($str);                    // $lengths 引數 表示 原始整個字串的 位元組的長度;   而應保證 $offset < $lengths; 否則都無字元可擷取; 
		
		while($chars<$len && $offset < $lengths){   // $chars<$len; 應是<  而不是<= ;因為是從0開始的,並執行迴圈擷取的;
			
			$higher = decbin(ord(substr($str,$offset,1)));  // 計算出 一個字元 中 第一個位元組(高位元組)的二進位制;
			
			if(strlen($higher) < 8){      // decbin()函式 轉換出來的 二進位制數 如果 <128(10000000) 的時候,即是二進位制長度<8位的時候,前面高位不預設補0;
				// 擷取一個位元組;(表示一個字元);
				$count = 1;
				
			}else if(substr($higher,0,3) == '110'){
				//擷取兩個位元組(表示一個字元);
				$count = 2;
				
			}else if(substr($higher,0,4) == '1110'){
				//擷取三個位元組(表示一個字元);
				$count = 3;
				
			}else if(substr($higher,0,5) == '11110'){
				//擷取四個位元組(表示一個字元);
				$count = 4;
				
			}else if(substr($higher,0,6) == '111110'){
				//擷取五個位元組(表示一個字元);
				$count = 5;
				
			}else if(substr($higher,0,7) == '1111110'){
				//擷取六個位元組(表示一個字元);
				$count = 6;
				
			}
			
			$res .= substr($str,$offset,$count);
			
			$offset += $count;
			
			$chars++;
			
		}
	
	return $res;
}

?>
<?php

//方法2:使用系統函式擷取
mb_substr(),不會亂碼.例:
$str = '換s幾ss個字實現中文字串擷取無亂碼的方法。';
echo mb_substr($str,0,5,'UTF-8');// '換s幾ss'

?>php
// 中文字串實現反轉;

$a = '我是一個好人';
function strrevv($str) {
	$strlen = mb_strlen($str,'UTF-8');
	$arr = array();
	for($a=0;$a<=$strlen;$a++) {
		
	    $arr[] = mb_substr($str,$a,1,'UTF-8');
	}
	
	$newstr = implode('',array_reverse($arr));
	return $newstr;
}
echo strrevv($a);

// mb_strlen(str,utf-8);   字串中字元的個數;

// mb_substr(str,start,length,utf-8); 多位元組字元的擷取;

// mb_strpos(str,needle,offset,utf-8);查詢子字串,在字串中出現的位置;

// mb_substr_count(str,needle,utf-8);統計子字串,在字串中出現的次數;