如何利用PHP來截取一段中文字符串而不出現亂碼

發表于:2007-05-25來源:作者:點擊數: 標簽:php截取一段字符串中文
標題:如何利用 PHP 來截取一段中文字符串而不出現亂碼 作者:jeffwu(327wu@263.net) [code:1:e818e36f81] /* 功能:截取全角和半角混合的字符串以避免亂碼 參數: $str_cut需要截斷的字符串 $length允許字符串顯示的最大長度 */ functionsubstr_cut$str_cut,

標題:如何利用PHP來截取一段中文字符串而不出現亂碼

作者:jeffwu(327wu@263.net)
[code:1:e818e36f81]
/*
功能:截取全角和半角混合的字符串以避免亂碼
參數:
$str_cut 需要截斷的字符串
$length  允許字符串顯示的最大長度

*/

function substr_cut($str_cut,$length = 30){ 

if (strlen($str_cut) > $length){
  for($i=0; $i < $length; $i++)
   if (ord($str_cut[$i]) > 128) $i++;
  $str_cut = substr($str_cut,0,$i) . "...";
}
return $str_cut;
}

[/code:1:e818e36f81]
說明:
程序的關鍵語句是:
[code:1:e818e36f81]
for($i=0; $i < $length; $i++)
if (ord($str_cut[$i]) > 128) $i++;

$str_cut = substr($str_cut,0,$i) . "...";
[/code:1:e818e36f81]
如果字符的ASCII碼大于128,說明當前字符和下一個字符是屬于一個漢字的。
則,$i++ 跳過對下一個字符的判斷。
再結合循環中的 $i++ ,實際上,當遇到一個漢字時,$i 就會加 2 ,從而正確的跳過漢字。
最終實現的效果是,$i 變量指向的要么是半角的字符,要么是全角漢字的首字符,不會指向
全角漢字的第二個字符,所以,當$i >= $length 時,循環結束,使用
$str_cut = substr($str_cut,0,$i) . "..."; 截取字符時自然也就不會出現亂碼了。


本人在寫一個程序時需要利用PHP從一段字符串中截取指定長度的一段字符下來。以前在寫ASP的時候,參考動網的程序寫過類似的程序,不過,還沒用PHP寫過。

想偷懶,看有不有現成的代碼可以用。于是,在GOOGLE中輸入:PHP 截斷字符 后查找到一段代碼。

全文:http://www.yesky.com/SoftChannel/72342371945349120/20020510/1610570_3.shtml

引用:
#########################################################################
  如何分別全角和半角以避免亂碼? 

  我們可以寫這樣一個函數來實現: 
[code:1:e818e36f81]
function ChgTitle($title) 

$length = 46; //我們允許字符串顯示的最大長度
if (strlen($title)>$length) { 
$temp = 0; 
for($i=0; $i<$length; $i++) 
if (ord($title[$i]) > 128) $temp++; 
if ($temp%2 == 0) 
$title = substr($title,0,$length)."..."; 
else 
$title = substr($title,0,$length+1)."..."; 

return $title; 
}  
[/code:1:e818e36f81]
  這個函數原理就是截斷一個字符,看看其ascII碼是不是大于128,如果是,說明截斷的是一個全角漢字,那么就退后一個截斷。用$length控制長度 

  備注:循環判斷字符串里面的 >128 的字符個數,如果半角字符為偶數,則表示位置剛好為整個漢字,如果為奇數,則為半個漢字,需要取下一個字符

#######################################################################

消化、測試這段代碼后發現有問題。經過反復調試,查找出,這段代碼基于的原理不正確。
它認為,漢字的兩個字節其ASCII碼都會大于128,其實不然,一個漢字的首個字節的ASCII碼
必定是大于128的,但是第二個字節的ASCII碼不一定大于128,例如:"祐",其兩個字節的ASCII
碼分別為:181 和 118。

經過仔細分析,最終,我利用上面的函數實現了對全角和半角字符串的截取。

一點點體會,寫出來也是想和大家一起交流、學習。我不知道是不是有人已經寫過上面的函數,不過,
我還沒能讀到,也就只能自己琢磨了,呵呵。

歡迎有興趣的朋友來信交流。

 longnetpro 回復于:2003-11-26 02:26:16
要想搞得更精確一點的話,請看GB2312的編碼規則

gb2313是這樣的,第一字節范圍是0x80 - 0xFE;第二字節范圍是 0x40 - 0xFE,但不能為0x7F。

還可以用正則表達式,假如你想得到前三十個漢字(不是字節),可用
/^([\x00-\x7F]|[\x80-\xFE][\x40-\x7E\x80-\xFE]){30}/

我用的方法一貫是:將多字節碼(如中文)轉換為UNICODE,長度自然就出來了。不過一般只針對長度比較短的字符串,因為在一般的PHP編程中很少需要分析長的多字節編碼的字符串(如求長度或是截取其中一部分),而且就算是不轉換成UNICODE循環也很慢,不值得推薦,肯定需要用到擴展模塊的(如mbstring多字節碼字符串模塊)。而用UNICODE轉換是比較通用的辦法,現在WINDOWS NT系列的操作系統都是用UNICODE作底層統一編碼的。

 netkiller 回復于:2003-11-26 09:01:02
哈哈..樓主例只,只能用于GB2312,如果是GB18030,GBK不知可以嗎????

[quote:bdf0b87f3e="longnetpro"]E\x80-\xFE]){30}/

我用的方法一貫是:將多字節碼(如中文)轉換為UNICODE,長度自然就出來了。不過一般只針對長度比較短的字符串,因為在一般的PHP編程中很少需要分析長的多字節編碼的字符串(如求長度或是截取?.........[/quote:bdf0b87f3e]

我的整個站點都是UTF-8的..數據庫使用UNICODE 數據存儲UTF-8

member=> select substring('數據庫的編碼是用系統表' from 1 for 4);

 substring

-----------

 數據庫的

(1 row)

 

member=> select substring('數據庫的編碼是用系統表' from 1 for 2);

 substring

-----------

 數據

(1 row)

 

member=> select * from 組;

序號 |     組名     |         描述

------+--------------+----------------------

    1 | 域用戶       | 9812.net域內用戶

    3 | 計算機維護組 | 維護計算機的用戶用戶

(2 rows)

 

member=> select 組名,substring(描述 from 1 for 5) as 描述 from 組;

     組名     |    描述

--------------+------------

 域用戶       | 9812.

 計算機維護組 | 維護計算機

(2 rows)

 longnetpro 回復于:2003-11-26 11:20:54
你這個是對特殊設置的數據庫可行,比較通用的辦法還是用PHP即時轉換吧。

我前一個月寫了一個漢字編碼轉換的程序,支持UTF8,UTF16BE、LE,UTF32BE、LE,GB18030,BIG5的互轉,支持繁簡互轉,中間代碼用UNICODE。
演示地址:
簡體
http://members.lycos.co.uk/longnetpro/encoding/
繁體
http://members.lycos.co.uk/longnetpro/encoding/?lang=cht

因為是演示版,并顧及到服務器安全性,因此我限制了它的很多功能,轉換也只限于UTF8,GB18030,BIG5,但該類本身的功能是完整的。

注意,如果是文件轉換,只能轉換TXT文件。

 netkiller 回復于:2003-11-26 17:06:51
[quote:3ae2976a31="longnetpro"]你這個是對特殊設置的數據庫可行,比較通用的辦法還是用PHP即時轉換吧。

我前一個月寫了一個漢字編碼轉換的程序,支持UTF8,UTF16BE、LE,UTF32BE、LE,GB18030,BIG5的互轉,支持繁簡互轉,中間代碼用UNICODE。
..........[/quote:3ae2976a31]

不支持UNICODE.的數據就是不合格產品..

你那么轉來轉去.煩不煩...影響性能...
如果要轉碼.使用iconv 函數就行了.編譯時加--with-iconv
數據本身也支持
select convert(描述,'UNICODE','GBK')as desc from 組;
select convert(組名 using utf_8_to_gb18030) from 組;

http://home.9812.net/linux/article/postgres/postgresql.htm

請看看..
11.8.2 PHP

 longnetpro 回復于:2003-11-26 20:35:36
[quote:87a95e989e="netkiller"]

不支持UNICODE.的數據就是不合格產品..

你那么轉來轉去.煩不煩...影響性能...
如果要轉碼.使用iconv 函數就行了.編譯時加--with-iconv
數據本身也支持
select convert(描述,'UNICODE','GBK')as desc from ?.........[/quote:87a95e989e]

不支持UNICODE的數據就是不合格產品?可能你這么認為,可很多老外并不這么認為的。其實說白了,UNICODE還是為了照顧非拉丁文字語言而搞的,它為什么一定要支持?因為UNICODE只是一個組織定的標準,并不一定被所有人認同,其實現在還有爭議。還有一個原因是UNICODE在很多情況下也并非絕對完美的方案。

你嫌煩就算了,又沒有要你用!性能和效率問題我已盡量考慮了。再說了,你要有所得必定有所失。

任何一種方法都有各自的優缺點的,什么事也不都是完全按你想象那樣來的,不是所有的人的需求和條件都和你一樣的。意外的情況也很多,但是只要你用得得法,用的場合得當,沒有什么不好的。不然的話,要是都明知道你的方法好,何必想方設法搞一些別的東西出來呢?一個東西的存在是有它存在的理由的,比如MS的產品,你能說它很好?但它為什么這么受歡迎?——當然你可能不喜歡它,我也不太喜歡它,但還是有很多人是喜歡它的。

所以以后發表結論的時候請客觀一點,看問題的視角多一點,不是只從自己出發。

 netkiller 回復于:2003-11-27 09:08:11
[quote:1addfc0608="longnetpro"]

不支持UNICODE的數據就是不合格產品?可能你這么認為,可很多老外并不這么認為的。其實說白了,UNICODE還是為了照顧非拉丁文字語言而搞的,它為什么一定要支持?因為UNICODE只是一個組織定的標準,并不一定被所有..........[/quote:1addfc0608]

這是直接使用UNICODE與間接使用... 的問題.

UNICODE還是為了照顧非拉丁文字語言而搞的..不是為了"照顧".
而是為了跨平臺兼容..

UNICODE 使你的數據庫可以存儲,中文(繁,簡,蒙古,藏文....),日文,韓文.啊拉伯..等等.....
一個中文漢字長=假名長=韓文長=啊拉伯字長=英文.......
好處不用說...

[quote:1addfc0608]
所以以后發表結論的時候請客觀一點,看問題的視角多一點,不是只從自己出發。 
[/quote:1addfc0608]

你可以看看我寫的文檔..
[url]http://home.9812.net/linux/article/postgres/postgresql.htm[/url]

11.8       漢字編碼問題


文中提供了.4轉碼方案.(包括原代碼) 視角還不夠多嗎? 目前還沒想出其它方案.

 longnetpro 回復于:2003-11-27 10:04:08
從postgresql的角度來說,你的方法是很好,也的確簡單易行。但并不是所有的用戶都是用這種數據庫的,也不是所有的用戶都是用這種方式的。也不是所有的數據庫都支持UNICODE的——因為現在就是存在有很多的“不合格產品”,你能怎么辦?并非說你的方法不好,也并非說UNICODE不好,我也用UNICODE,我也需要轉換。我所說的多視角也并非指方案有多少(你的所有方案都只是基于postgresql的),而是說不能只站在你熟悉的角度上看問題。你的好的方法和建議我會接受的。

 netkiller 回復于:2003-11-27 10:26:01
我的方法同樣適合SQL99的數據.如Oracle

一般不合格數據都是SQL92的.如果他不支持UNICODE.為什么拿到其它國家銷售呢..???哈哈...
:)

MS Sqlserver , Sybase 雖然是SQL92但他加了很多自己東東.跟本不是ASNI 的SQL?。病。樱眩蹋梗?br>
 znsoft 回復于:2003-11-28 10:19:29
hehe,這段代碼最早是我在phpease.com發表的,來源于幾年前作的漢字顯示研究:)

往事不在,phpease.com也關門, 當年php紅火的場面也不在了,但欣慰的是用php 的人越來越多了

上面的邊界字符還有問題,最好的是判斷

是否大于0xa0,這是漢字的第一個字符開始的編碼

 netkiller 回復于:2003-11-28 11:44:40
哈哈.phpease.com 我和站長聊過..
我讓他和其它站合作..走合并路..

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97