文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>如何利用PHP来截取一段中文字符串而不出现乱码

如何利用PHP来截取一段中文字符串而不出现乱码

时间:2007-02-17  来源:PHP爱好者

标题:如何利用PHP来截取一段中文字符串而不出现乱码

作者:jeffwu([email protected])
[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-x7Ex80-xFE]){30}/

我用的方法一贯是:将多字节码(如中文)转换为UNICODE,长度自然就出来了。不过一般只针对长度比较短的字符串,因为在一般的PHP编程中很少需要分析长的多字节编码的字符串(如求长度或是截取其中一部分),而且就算是不转换成UNICODE循环也很慢,不值得推荐,肯定需要用到扩展模块的(如mbstring多字节码字符串模块)。而用UNICODE转换是比较通用的办法,现在WINDOWS NT系列的操作系统都是用UNICODE作底层统一编码的。

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

[quote:bdf0b87f3e="longnetpro"]Ex80-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]

你可以看看我写的文档..
php爱好者站 http://www.phpfans.net 网页特效|网页模板
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载