参考编码规则以及php文档的一个例子,实现了将gbk字符串拆字的小玩具,很简陋没有容错处理等等! 基本上利用了如下规则: utf-8 和 gbk 中 ascii 单字节部分不变 utf-8 编码中,注意除掉第一个字节以外的其他(对于单字节来说范围就是 0 ~ 0x7f) 多字节来说每一个字节的编码范围 0x80 ~ 0xbf(10xxxxxx ) U-00000000 - U-0000007F: 0xxxxxxx ascii U-00000080 - U-000007FF: 110xxxxx 10xxxxxx 0xc0~0xdf U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 0xe0~0xef U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 0xf0~0xf7 U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 0xf8~0xfb U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 0xfc~0xfd GBK 除ascii编码部分以外采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。总计 23940 个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。
#! /home/lixiaobo/dsp/trunk/spider/php
<?php
function str_split_php4_utf8($str) {
// place each character of the string into and array
$split=1;
$array = array();
for ( $i=0; $i < strlen( $str ); ){
$value = ord($str[$i]);
if($value > 0x7f){
if($value >= 0xc0 && $value <= 0xdf) // 双字节
$split=2;
elseif($value >= 0xe0 && $value <= 0xef) // 三字节
$split=3;
elseif($value >= 0xf0 && $value <= 0xf7) // 四字节
$split=4;
}else{
$split=1;
}
$key = NULL;
for ( $j = 0; $j < $split; $j++, $i++ ) {
$key .= $str[$i];
}
array_push( $array, $key );
}
return $array;
}
function str_split_php4_gbk($str) {
// place each character of the string into and array
$split=1;
$array = array();
for ( $i=0; $i < strlen( $str ); ){
$value = ord($str[$i]);
if($value > 0x81 && $value < 0xFE){
$split=2;
}else{
$split=1;
}
$key = NULL;
for ( $j = 0; $j < $split; $j++, $i++ ) {
$key .= $str[$i];
}
array_push( $array, $key );
}
return $array;
}
?>
再贴一段一个牛人写的utf-8 编码识别模块,我给他加了点注释
<?php
function isValidUtf8($string)
{
$str_len = strlen($string);
for($i=0;$i<$str_len;)
{
$str = ord($string[$i]);
if($str>=0 && $str < 0¡Á7f)
{
$i++;
continue; // 单字节的跳过
}
if($str< 0xc0 || $str>0xfd) return false; // utf-8 首字节范围 0xc0 ~ 0xfd
$count = $str>0xfc?5:$str>0xf8?4:$str>0xf0?3:$str>0xe0?2:1; // 已经读了一个字节的基础上,接着往后读字节的个数,参照utf-8 编码规则
if($i+$count > $str_len) return false; // 已经读过的字节数加上需要跳过的字节数居然大于总长度,走人
$i++; // 来到第二个字节
for($m=0;$m<$count;$m++)
{
// 第二个字节以及以后的所有字节范围都是在 0x80 ~ 0xbf
if(ord($string[$i])<0x80 || ord($string[$i])>0xbf) return false;
$i++;
}
}
return true;
}
?>
原出处见: http://my.donews.com/sawfish/2007/05/01/%E5%AD%97%E7%AC%A6%E9%9B%86%E7%BC%96%E7%A0%81%E7%9A%84%E8%AF%86%E5%88%AB%EF%BC%88%E4%B8%80%EF%BC%89/
自己理解的关于cp936:
以 “中”字为例,其 GBK 编码为 d6d0, 在cp936.txt 中可以找到对应unicode的为:
0x4E2D(UCS-2编码), 这样就通过cp936实现内码转换,同理cp950实现的是BIG5码到ucs2的内码转换